Authentication
Authenticate API requests using API keys or JWT tokens
All API requests require authentication. Hadrian supports multiple authentication methods that can be used individually or combined.
API Key Authentication
API keys are the simplest way to authenticate programmatic access. Keys are prefixed with gw_ by default.
Request Headers
Use either header format:
# X-API-Key header (default)
curl http://localhost:8080/v1/chat/completions \
-H "Content-Type: application/json" \
-H "X-API-Key: gw_live_abc123..." \
-d '{"model": "gpt-4o", "messages": [{"role": "user", "content": "Hello"}]}'
# Authorization header (OpenAI-compatible)
curl http://localhost:8080/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer gw_live_abc123..." \
-d '{"model": "gpt-4o", "messages": [{"role": "user", "content": "Hello"}]}'Configuration
[auth.mode]
type = "api_key"
[auth.api_key]
header_name = "X-API-Key" # or "Authorization" for Bearer tokens
key_prefix = "gw_" # Required prefix for all keys
cache_ttl_secs = 300 # Cache key lookups for 5 minutesCreating API Keys
Create keys via the Admin API or web UI:
# Create an API key for a user
curl -X POST http://localhost:8080/admin/v1/api_keys \
-H "Content-Type: application/json" \
-H "X-API-Key: $ADMIN_KEY" \
-d '{
"name": "Production API Key",
"user_id": "user_abc123",
"expires_at": "2025-12-31T23:59:59Z"
}'Response:
{
"id": "key_abc123",
"name": "Production API Key",
"key": "gw_live_sk_abc123...",
"created_at": "2024-01-15T10:00:00Z",
"expires_at": "2025-12-31T23:59:59Z"
}The full API key is only returned once during creation. Store it securely.
JWT Authentication
Use JWT tokens from your identity provider (IdP) for service-to-service authentication or SSO. JWT validation is configured per-organization through SSO configs in the Admin UI — there is no global JWT configuration.
Request Format
curl http://localhost:8080/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..." \
-d '{"model": "gpt-4o", "messages": [{"role": "user", "content": "Hello"}]}'Per-Org JWT Routing
In idp mode, each organization configures their own identity provider (OIDC or SAML) via the Admin UI. When a JWT is presented, the gateway:
- Decodes the
iss(issuer) claim from the token - Matches the issuer to the correct organization's SSO config
- Validates the token against that organization's IdP JWKS keys
This happens automatically — no per-org JWT configuration is needed in the config file. Configure SSO for each organization through Admin > Organizations > [Org] > SSO.
See the SSO Admin Guide for setup instructions.
Per-org JWT validation requires [auth.mode] set to type = "idp". Each organization's SSO
config provides the issuer URL, JWKS endpoint, and claim mappings.
Supported Algorithms
| Algorithm | Description |
|---|---|
| RS256, RS384, RS512 | RSA signatures (recommended) |
| ES256, ES384, ES512 | ECDSA signatures |
| HS256, HS384, HS512 | HMAC signatures (shared secret) |
Combined Authentication (IdP Mode)
IdP mode combines API key and JWT authentication. The gateway tries each method in order, with JWT validation provided automatically by per-org SSO configs.
[auth.mode]
type = "idp"
[auth.api_key]
header_name = "X-API-Key"
key_prefix = "gw_"With this configuration:
- If
X-API-Keyheader is present, validate as API key - If
Authorization: Bearerheader is present with JWT format, validate against the issuer's per-org SSO config - If
Authorization: Bearerheader is present withgw_prefix, validate as API key
JWT validation in idp mode is fully automatic. Each organization's SSO config (configured via
the Admin UI) provides the issuer, JWKS endpoint, and claim mappings. No JWT settings are needed
in the config file.
Error Responses
All authentication errors return HTTP 401 with a consistent error format:
| Error Code | Description | Solution |
|---|---|---|
invalid_api_key | Key not found or malformed | Check key format and prefix |
key_revoked | Key has been revoked | Generate a new key |
key_expired | Key past expiration date | Generate a new key |
invalid_token | JWT malformed or invalid | Check token format |
token_expired | JWT past expiration | Obtain fresh token from IdP |
invalid_issuer | JWT issuer doesn't match | Verify issuer in SSO config |
invalid_audience | JWT audience doesn't match | Verify audience in SSO config |
jwks_fetch_failed | Cannot reach JWKS URL | Check network connectivity |
Example Error Response
{
"error": {
"message": "Invalid API key",
"type": "authentication_error",
"code": "invalid_api_key"
}
}Rate Limiting Headers
Authenticated requests include rate limit information in response headers:
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 995
X-RateLimit-Reset: 1705320000| Header | Description |
|---|---|
X-RateLimit-Limit | Maximum requests per window |
X-RateLimit-Remaining | Requests remaining in window |
X-RateLimit-Reset | Unix timestamp when window resets |
Security Best Practices
- Never commit API keys - Use environment variables or secrets managers
- Set expiration dates - Rotate keys regularly
- Use scoped keys - Create separate keys for different environments
- Monitor usage - Check audit logs for unusual activity
- Use HTTPS - Never send credentials over unencrypted connections