JWT Authentication
JWT Authentication
Separation of Duties: See Separation of Duties - API documentation is responsible for documenting APIs. It does NOT own agent manifests, execution, or infrastructure configuration.
JSON Web Token authentication for API access across the Bluefly platform.
Overview
All platform APIs use JWT (JSON Web Token) for authentication:
- Token-based auth: Stateless authentication via JWT
- Unified auth service: Centralized authentication (Compliance Engine)
- Role-based access: RBAC with granular permissions
- Token rotation: Automatic token refresh
- Audit logging: Complete authentication audit trails
Architecture
graph LR A[Client] -->|1. Login| B[Auth Service] B -->|2. JWT| A A -->|3. API Request + JWT| C[API Gateway] C -->|4. Verify JWT| D[Token Validator] D -->|5. Allow/Deny| C C -->|6. Response| A
Getting a JWT Token
1. Username/Password Login
POST /api/v1/auth/login Content-Type: application/json
Request:
{ "username": "developer@bluefly.io", "password": "secure-password-123", "client_id": "llm-platform-web", "grant_type": "password" }
Response:
{ "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...", "refresh_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...", "token_type": "Bearer", "expires_in": 3600, "scope": "read write admin" }
2. API Key Authentication
For service-to-service authentication:
POST /api/v1/auth/api-key Content-Type: application/json
Request:
{ "api_key": "sk_live_abc123...", "client_id": "agent-brain-service" }
Response:
{ "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...", "token_type": "Bearer", "expires_in": 3600, "service": "agent-brain", "permissions": ["agent:execute", "mesh:communicate"] }
3. OAuth 2.0 (GitLab)
For user authentication via GitLab OAuth:
See OAuth 2.0 Guide for complete flow.
Using JWT Tokens
Authorization Header
Include JWT in the Authorization header:
curl -X GET https://gateway.local.bluefly.io/api/v1/chat/completions \ -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..." \ -H "Content-Type: application/json" \ -d '{ "model": "auto-route", "messages": [{"role": "user", "content": "Hello"}] }'
Query Parameter (Not Recommended)
For WebSocket or legacy clients only:
ws://tracer.local.bluefly.io/api/v1/traces/stream?access_token=eyJhbGci...
Warning: Query parameters appear in logs. Use Authorization header whenever possible.
JWT Token Structure
JWT tokens are signed with RS256 (RSA SHA-256):
Header
{ "alg": "RS256", "typ": "JWT", "kid": "auth-key-2025-01" }
Payload
{ "sub": "user-123", "iss": "https://auth.bluefly.io", "aud": ["https://gateway.local.bluefly.io"], "exp": 1705323600, "iat": 1705320000, "nbf": 1705320000, "jti": "token-abc123", "scope": "read write", "roles": ["developer", "agent-admin"], "permissions": [ "agent:execute", "mesh:communicate", "workflow:create" ], "user": { "id": "user-123", "email": "developer@bluefly.io", "name": "John Developer" }, "client_id": "llm-platform-web" }
Signature
RSASHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
privateKey
)
Token Claims
| Claim | Description | Required |
|---|---|---|
sub | Subject (user ID) | |
iss | Issuer (auth service) | |
aud | Audience (target service) | |
exp | Expiration time (Unix timestamp) | |
iat | Issued at (Unix timestamp) | |
nbf | Not before (Unix timestamp) | |
jti | JWT ID (unique identifier) | |
scope | OAuth 2.0 scopes | |
roles | User roles | |
permissions | Granular permissions | |
user | User metadata | |
client_id | Client identifier |
Token Refresh
Refresh expired access tokens using refresh token:
POST /api/v1/auth/refresh Content-Type: application/json
Request:
{ "refresh_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...", "grant_type": "refresh_token" }
Response:
{ "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...", "refresh_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...", "token_type": "Bearer", "expires_in": 3600 }
Token Revocation
Revoke a token before expiration:
POST /api/v1/auth/revoke Content-Type: application/json Authorization: Bearer eyJhbGci...
Request:
{ "token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...", "token_type_hint": "access_token" }
Response:
{ "revoked": true, "jti": "token-abc123", "revokedAt": "2025-01-15T10:35:00Z" }
Token Validation
Client-Side Validation
Validate JWT locally without API call:
TypeScript:
import * as jose from 'jose'; const JWKS_URL = 'https://auth.bluefly.io/.well-known/jwks.json'; async function validateToken(token: string) { const JWKS = jose.createRemoteJWKSet(new URL(JWKS_URL)); const { payload } = await jose.jwtVerify(token, JWKS, { issuer: 'https://auth.bluefly.io', audience: 'https://gateway.local.bluefly.io' }); return payload; }
Server-Side Validation
Validate via auth service:
POST /api/v1/auth/validate Content-Type: application/json
Request:
{ "token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..." }
Response:
{ "valid": true, "payload": { "sub": "user-123", "exp": 1705323600, "roles": ["developer"], "permissions": ["agent:execute"] } }
Invalid Token:
{ "valid": false, "error": "token_expired", "message": "Token expired at 2025-01-15T10:00:00Z" }
Public Keys (JWKS)
Get public keys for JWT verification:
GET /.well-known/jwks.json
Response:
{ "keys": [ { "kty": "RSA", "kid": "auth-key-2025-01", "use": "sig", "alg": "RS256", "n": "xGOr-H7A...", "e": "AQAB" }, { "kty": "RSA", "kid": "auth-key-2024-12", "use": "sig", "alg": "RS256", "n": "yH1s-K8B...", "e": "AQAB" } ] }
Error Responses
401 Unauthorized
{ "error": { "type": "authentication_error", "code": "invalid_token", "message": "Invalid or expired JWT token", "details": { "reason": "token_expired", "expiredAt": "2025-01-15T10:00:00Z" } } }
403 Forbidden
{ "error": { "type": "authorization_error", "code": "insufficient_permissions", "message": "User lacks required permission", "details": { "required": "agent:execute", "userPermissions": ["agent:read"] } } }
Security Best Practices
1. Token Storage
Recommended:
- Store in memory (React state, etc.)
- Use secure HTTP-only cookies
- Use secure session storage
Avoid:
- LocalStorage (XSS vulnerable)
- URL parameters (logged everywhere)
- Unencrypted cookies
2. Token Lifetime
Access Tokens: Short-lived (1 hour) Refresh Tokens: Long-lived (30 days)
3. Token Rotation
Automatically rotate tokens:
- Before expiration (proactive refresh)
- After security events (force re-auth)
- During key rotation (seamless transition)
4. Scope Limitation
Request only required scopes:
{ "scope": "agent:read workflow:execute" }
Don't request admin unless absolutely necessary.
Rate Limiting
JWT authentication is rate-limited:
| Operation | Limit | Window |
|---|---|---|
| Login | 10 attempts | 15 minutes |
| Token refresh | 100 requests | 1 hour |
| Token validation | 1000 requests | 1 minute |
Rate Limit Headers:
X-RateLimit-Limit: 10
X-RateLimit-Remaining: 7
X-RateLimit-Reset: 1705320900
Client Libraries
TypeScript
import { AuthClient } from '@bluefly/auth-client'; const auth = new AuthClient({ endpoint: 'https://auth.bluefly.io', clientId: 'llm-platform-web' }); // Login const { access_token, refresh_token } = await auth.login({ username: 'developer@bluefly.io', password: 'secure-password' }); // Automatic token refresh const apiClient = auth.createClient({ baseURL: 'https://gateway.local.bluefly.io', autoRefresh: true }); // Use authenticated client const response = await apiClient.post('/api/v1/chat/completions', { model: 'auto-route', messages: [{ role: 'user', content: 'Hello' }] });
Python
from bluefly import AuthClient auth = AuthClient( endpoint="https://auth.bluefly.io", client_id="llm-platform-cli" ) # Login tokens = auth.login( username="developer@bluefly.io", password="secure-password" ) # Use access token api = auth.create_client( base_url="https://gateway.local.bluefly.io", auto_refresh=True ) response = api.post("/api/v1/chat/completions", json={ "model": "auto-route", "messages": [{"role": "user", "content": "Hello"}] })
Audit Logging
All authentication events are logged:
{ "eventType": "login_success", "userId": "user-123", "timestamp": "2025-01-15T10:00:00Z", "ip": "192.168.1.100", "userAgent": "Mozilla/5.0...", "clientId": "llm-platform-web", "metadata": { "mfa": false, "provider": "local" } }
See Security Architecture for audit details.