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

  1. Decodes the iss (issuer) claim from the token
  2. Matches the issuer to the correct organization's SSO config
  3. 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

AlgorithmDescription
RS256, RS384, RS512RSA signatures (recommended)
ES256, ES384, ES512ECDSA signatures
HS256, HS384, HS512HMAC 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:

  1. If X-API-Key header is present, validate as API key
  2. If Authorization: Bearer header is present with JWT format, validate against the issuer's per-org SSO config
  3. If Authorization: Bearer header is present with gw_ 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 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 SSO config
invalid_audienceJWT audience doesn't matchVerify audience in SSO 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