32. JWT Standardization Across All Authentication Flows
Date: 2025-01-28Status
AcceptedCategory
Authentication & AuthorizationContext
Authentication systems often support multiple token formats (sessions, cookies, opaque tokens, JWTs, API keys) leading to complexity in validation, authorization, and client integration. This creates challenges:- Inconsistent Validation: Different code paths for each token type
- Authorization Complexity: Permission checks must handle multiple formats
- Client Confusion: Different authentication methods require different implementations
- Security Gaps: Inconsistent validation rules across token types
- Operational Burden: Multiple token management systems to monitor
- Federation Issues: External identity providers return different token formats
Decision
We will standardize on JSON Web Tokens (JWT) as the sole authentication token format across all authentication flows. All authentication methods will produce a JWT, and all validation will use JWT verification.Core Principles
- Universal JWT Output: Every authentication method produces a JWT
- Stateless Validation: JWTs validated without database lookups
- Keycloak as Issuer: All JWTs issued by Keycloak (single issuer)
- RS256 Signing: Asymmetric cryptography (public key validation)
- Standard Claims: Consistent JWT structure across all flows
- Refresh Token Pattern: Short-lived JWTs with refresh tokens
JWT Structure
Authentication Flows → JWT
- User Login (Password):
User → Keycloak (ROPC) → JWT + Refresh Token - Federated Identity:
User → External IdP → Keycloak → JWT + Refresh Token - API Key:
Client → Kong (validate) → Keycloak → JWT - Service Principal:
Service → Keycloak (client_credentials) → JWT + Refresh Token - Token Refresh:
Client → Keycloak (refresh_token) → New JWT
Token Lifetimes
Consequences
Positive Consequences
- Unified validation (single code path)
- Stateless architecture, scalability via public key cryptography
- Standard protocol (RFC 7519) with ecosystem support
- Client simplicity, federation compatible
- Authorization ready (user context embedded)
Negative Consequences
- Token size larger than opaque tokens (200-2000 bytes)
- Revocation challenge (cannot revoke before expiration without blacklist)
- Refresh complexity (clients must implement refresh logic)
- Short lifetime issues for long-running tasks
- Clock synchronization required
Mitigation Strategies
- Revocation: Hybrid mode with server-side sessions (optional), Redis blacklist for emergencies
- Long-Running: Service principals get 30-day refresh tokens, server-side storage, auto-refresh
- Token Size: Minimize custom claims, gzip compression
- Key Rotation: Automated JWKS fetching (1-hour cache), gradual rotation
Alternatives Considered
- Opaque Tokens: Rejected - requires DB lookup, stateful, poor scalability
- Mixed Tokens: Rejected - multiple code paths, inconsistent authorization
- Macaroons: Rejected - non-standard, complex, over-engineered
- OAuth2 Introspection: Rejected - latency, stateful, network dependency
Implementation Details
JWT Issuance (src/mcp_server_langgraph/auth/keycloak.py:245-294):
src/mcp_server_langgraph/auth/keycloak.py:89-219):
References
- JWT Verification:
src/mcp_server_langgraph/auth/keycloak.py:89-219 - Authentication:
src/mcp_server_langgraph/auth/keycloak.py:245-294 - Related ADRs: ADR-0007, ADR-0031, ADR-0034, ADR-0035, ADR-0036
- External: RFC 7519 (JWT), RFC 7515 (JWS), OIDC Core 1.0