Hadrian is experimental alpha software. Do not use in production.
Hadrian

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.gateway]
type = "api_key"

[auth.gateway.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 minutes

Creating 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.

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"}]}'

Configuration

[auth.gateway]
type = "jwt"
issuer = "https://auth.example.com"
audience = "hadrian"
jwks_url = "https://auth.example.com/.well-known/jwks.json"

# Optional: Map JWT claims to user identity
[auth.gateway.jwt.claims]
user_id = "sub"           # Use 'sub' claim as user ID
email = "email"           # Use 'email' claim
org_id = "org_id"         # Custom claim for organization

Supported Algorithms

AlgorithmDescription
RS256, RS384, RS512RSA signatures (recommended)
ES256, ES384, ES512ECDSA signatures
HS256, HS384, HS512HMAC signatures (shared secret)

Multi-Auth Mode

Combine API key and JWT authentication. The gateway tries each method in order.

[auth.gateway]
type = "multi"

[auth.gateway.api_key]
header_name = "X-API-Key"
key_prefix = "gw_"

[auth.gateway.jwt]
issuer = "https://auth.example.com"
audience = "hadrian"
jwks_url = "https://auth.example.com/.well-known/jwks.json"

With this configuration:

  1. If X-API-Key header is present, validate as API key
  2. If Authorization: Bearer header is present with JWT format, validate as JWT
  3. If Authorization: Bearer header is present with gw_ prefix, validate as API key

Error Responses

All authentication errors return HTTP 401 with a consistent error format:

Error CodeDescriptionSolution
invalid_api_keyKey not found or malformedCheck key format and prefix
key_revokedKey has been revokedGenerate a new key
key_expiredKey past expiration dateGenerate a new key
invalid_tokenJWT malformed or invalidCheck token format
token_expiredJWT past expirationObtain fresh token from IdP
invalid_issuerJWT issuer doesn't matchVerify issuer in config
invalid_audienceJWT audience doesn't matchVerify audience in config
jwks_fetch_failedCannot reach JWKS URLCheck 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
HeaderDescription
X-RateLimit-LimitMaximum requests per window
X-RateLimit-RemainingRequests remaining in window
X-RateLimit-ResetUnix timestamp when window resets

Security Best Practices

  1. Never commit API keys - Use environment variables or secrets managers
  2. Set expiration dates - Rotate keys regularly
  3. Use scoped keys - Create separate keys for different environments
  4. Monitor usage - Check audit logs for unusual activity
  5. Use HTTPS - Never send credentials over unencrypted connections

On this page