Authentication
Ash uses Bearer token authentication to protect API endpoints. All requests to /api/* routes require a valid API key. Authentication is always enabled — the server auto-generates an API key on first start if one is not provided.
Auto-Generated API Key
When you run ash start for the first time, the server automatically generates a secure API key (prefixed ash_) and:
- Stores the hashed key in the database.
- Writes the plaintext key to
~/.ash/initial-api-key. - Logs the key to stdout.
The CLI automatically picks up this key and saves it to ~/.ash/config.json. No manual configuration is needed for local development.
Manual Configuration
To use a specific API key instead of the auto-generated one, set the ASH_API_KEY environment variable:
export ASH_API_KEY="your-key-here"
Or pass it when starting the server:
ash start -e ASH_API_KEY=your-key-here
When ASH_API_KEY is set, the server uses it directly instead of auto-generating one.
Sending Authenticated Requests
- TypeScript
- Python
- CLI
- curl
Pass the API key when creating the client:
import { AshClient } from '@ash-ai/sdk';
const client = new AshClient({
serverUrl: 'http://localhost:4100',
apiKey: 'your-generated-key-here',
});
// All subsequent calls include the Authorization header automatically
const agents = await client.listAgents();
from ash_sdk import AshClient
client = AshClient(
"http://localhost:4100",
api_key="your-generated-key-here",
)
agents = client.list_agents()
Set the ASH_API_KEY environment variable:
export ASH_API_KEY="your-generated-key-here"
ash agent list
Or pass it inline:
ASH_API_KEY="your-generated-key-here" ash agent list
Include the Authorization header with the Bearer scheme:
curl $ASH_SERVER_URL/api/agents \
-H "Authorization: Bearer your-generated-key-here"
Public Endpoints
The following endpoints do not require authentication, even when ASH_API_KEY is set:
| Endpoint | Description |
|---|---|
GET /health | Server health check |
GET /metrics | Prometheus metrics |
GET /docs/* | API documentation (Swagger UI) |
Error Responses
401 -- Missing Authorization Header
Returned when the request has no Authorization header:
{
"error": "Missing Authorization header",
"statusCode": 401
}
401 -- Invalid API Key
Returned when the Authorization header is present but the key does not match:
{
"error": "Invalid API key",
"statusCode": 401
}
401 -- Malformed Header
Returned when the Authorization header does not use the Bearer <key> format:
{
"error": "Invalid Authorization header format",
"statusCode": 401
}
Auth Resolution Order
When a request arrives, the server resolves authentication in the following order:
- Public endpoints (
/health,/docs/*) -- skip auth entirely. - Internal endpoints (
/api/internal/*) -- authenticated viaASH_INTERNAL_SECRET(used for runner registration). - Bearer token present -- validate against
ASH_API_KEYor the database API keys table. Accept if matched. - No match -- reject with 401.