Guides
Authentication & Gateway
Authentication & Gateway
This guide describes the Kong + Keycloak solution that fronts every /llm/* request in Jan Server. The implementation uses Kong OSS plugins (jwt + keycloak-apikey) so the edge accepts Keycloak-issued JWTs or scoped API keys before requests reach the microservices.
1. Architectural Overview
- Kong gateway (
http://localhost:8000) is the sole public endpoint for Jan Server. Every API (LLM, Response, Media, MCP, auth) is exposed through Kong routes that perform JWT/API-key validation, rate limiting, request transformation, and header sanitation. - Keycloak (realm
jan) issues OAuth2/OIDC tokens. Services and Kong both depend on the Keycloak JWKS endpoint (http://keycloak:8085/realms/jan/protocol/openid-connect/certs) for signature validation. - LLM API is responsible for guest onboarding, API key lifecycle endpoints, and the
/auth/validate-api-keycallback consumed by the Kong plugin. - Custom auth plugin (
keycloak-apikey) replaces Kong consumers/credentials in DB-less mode by delegating API key validation to the service layer.
2. Kong Authentication Flow
| Plugin | Purpose | Key config |
|---|---|---|
jwt | Validates Keycloak JWTs | key_claim_name: iss, claims_to_verify: ["exp","nbf"], maximum_expiration: 3600, anonymous: kong-anon-jwt, secret_is_base64: false, run_on_preflight: false |
keycloak-apikey | Validates API keys via LLM API | validation_url: http://llm-api:8080/auth/validate-api-key, hide_credentials: true, validation_timeout: 5000, run_on_preflight: false |
request-termination (anonymous fallback) | Returns 401 when neither plugin runs |
The routes define OR logic: requests are accepted if either the JWT or API key plugin succeeds. Kong also injects X-Auth-Method (value jwt or apikey) and user context headers (X-User-ID, X-User-Subject, X-User-Email, X-User-Username) so downstream services know who authenticated the call.
Flowchart
Client
+--> Kong Gateway (`/llm/*`)
+-- JWT Plugin (Keycloak)
| +--> Valid token -> Add `X-Auth-Method: jwt`, inject user headers -> Upstream
+-- API Key Plugin (`keycloak-apikey`)
| +--> Forward `X-API-Key` to `llm-api/auth/validate-api-key`
| +--> LLM API hashes key, consults Keycloak -> Valid -> Inject headers + `X-Auth-Method: apikey`
+-- Request-termination (fallback) -> Return 4013. Guest Tokens
- Endpoint:
POST /llm/auth/guest-loginexposed through Kong (/llm/auth/guest-loginroute). This endpoint creates a temporary Keycloak user and returnsaccess_token,refresh_token, and metadata. Guest tokens are meant for quick local testing; they honor rate limits and expire around 5 minutes. - Temporary Email: Guest users are automatically assigned a temporary email in the format
guest-{uuid}@temp.jan.aito satisfy Keycloak's email requirements. This temporary email is replaced with the real email when the guest account is upgraded viaPOST /auth/upgrade. - Usage: Include
Authorization: Bearer <token>on/v1/*calls or sent via Kong usingcurl -X POST http://localhost:8000/llm/auth/guest-login. Kong forwards the request tollm-apiand enforces the auth plugin (JWT may succeed immediately after issuance). - Upgrade: Call
POST /auth/upgradewith the guest token to convert to a permanent account. The upgrade endpoint overwrites the temporary email with a real email and marks it as verified, and changes theguestattribute fromtruetofalse. - Refresh: Call
/llm/auth/refresh-tokenor rely on Kong's JWT verification for new tokens in production flows.
4. API Key Lifecycle
- Format: Keys use the
sk_prefix plus 32 random characters. The shared secret is shown only once (on creation). Services store only the SHA-256 hash inside Keycloak user attributes and PostgreSQL (api_keystable from000001_init_schema.up.sql). - Endpoints (require JWT auth):
POST /auth/api-keys- Create a new API key tied to the authenticated user.GET /auth/api-keys- List active keys for the calling user.DELETE /auth/api-keys/{id}- Revoke a key.POST /auth/validate-api-key- Public validation endpoint called by Kong's plugin.- Validation Flow:
- Kong receives
X-API-Keyfrom the client. keycloak-apikeycallshttp://llm-api:8080/auth/validate-api-key.- LLM API hashes the key, compares it against Keycloak attributes, and responds with user data (or
401when invalid). - Kong injects user headers and marks the request as authenticated (can now enforce rate limits per consumer).
5. Keycloak Integration Notes
- JWKS: The Kong
jwtplugin fetches the Keycloak JWKS manually (no dynamic JWKS refresh). Rotate Keycloak signing keys via a manual Kong restart or redeploy the gateway. - Admin API: Credentials (JWT secrets) live only in the Kong Admin API and are never committed to Git. The gateway does not create consumers dynamically in DB-less mode, which keeps configuration declarative (
kong.yml). - Guest users: Each guest login request creates a temporary Keycloak user with a temporary email (
guest-{uuid}@temp.jan.ai) and theguestattribute set totrue. These users can be upgraded to permanent accounts via/auth/upgrade, which replaces the temporary email with a real one and toggles theguestflag tofalse. Upgrade and refresh flows use the samejanrealm policies as regular users.
6. Environment & Deployment Guidance
- Overlays: Use environment-specific Kong overlays (
docker,k8s/jan-server/templates, etc.) to toggle TLS verification (ssl_verify: falsein development,trueplus CA bundles in staging/prod). - Rate limiting: Kong enforces per-IP limits at the gateway plus per-consumer bucketed limits where a consumer is resolved either from JWT claims (
iss->keycloak-issuer) or from API key metadata. - Plugin loading: Custom
keycloak-apikeycode lives inkong/plugins/keycloak-apikey/(handler + schema + README). Compose mounts../kong/plugins:/usr/local/kong/plugins:roand setsKONG_PLUGINS: bundled,keycloak-apikey. - Credentials: The plugin uses
hide_credentials: trueso backend services never see the rawX-API-Key.
7. Observability & Follow-up
- Metrics: Expose plugin-specific stats for auth method usage and failure reasons. Consider adding Redis caching for
validate-api-keyresponses to reduce latency. - Logging: Kong logs record which plugin succeeded; look for
X-Auth-Methodinrequest-transformer-injected headers. - Tests: jan-cli api-test suites verify
/auth/api-keys,/llm/auth/guest-login, and thevalidate-api-keycall. Runmake test-authin development.
8. Security Hardening Summary
- Hashed secrets: API key secrets are hashed with SHA-256 and stored inside Keycloak user attributes to avoid storing plaintext tokens.
- Single-use visibility: Keys are shown only once (creation response) to prevent accidental leaks.
- Fallback response:
request-terminationreturns401when neither plugin authenticates, preventing unauthenticated requests from reaching services. - Anonymous consumer: The
kong-anon-jwtanonymous consumer is configured purely for the OR logic gate; it has no access beyond the gateway.
This document replaces the implementation roadmap formerly captured in auth-todo.md. Keep it updated whenever you add authentication routes, adjust Kong plugins, or change Keycloak realms.