JWT Authentication Configuration Guide¶
Version: 2.0.1 Last Updated: 2026-09-15 Git Commit: 61384b4a Author: Lincoln
Overview¶
JAiRouter supports JWT (JSON Web Token) authentication, which can be integrated with existing identity authentication systems. JWT authentication provides a stateless authentication mechanism and supports token refresh and blacklist functionalities.
Features¶
- Standard JWT Support: Fully compatible with RFC 7519 standard
- Multiple Signing Algorithms: Supports HS256, HS384, HS512, RS256, RS384, RS512
- Token Refresh: Supports access token and refresh token mechanisms
- Blacklist Functionality: Supports token revocation and logout
- Coexistence with API Key: Can be used alongside API Key authentication
- Username/Password Login: Supports obtaining JWT tokens via username and password
- Persistent Storage: Supports storing JWT accounts and token information in H2 database
- H2 Database Default Storage: H2 database is the default persistent storage method for JWT data
Quick Start¶
1. Enable JWT Authentication¶
Configuration file: config/auth/jwt.yml
jairouter:
security:
jwt:
enabled: true
secret: "${JWT_SECRET}"
algorithm: "HS256"
expiration-minutes: 60
jwt-header: "Jairouter_Token" # Custom JWT header
2. Set JWT Key¶
Symmetric Key (HS256/HS384/HS512)¶
# Production Environment JWT Key Configuration
export JWT_SECRET="your-very-strong-production-jwt-secret-key-at-least-32-characters-long"
Token lifetimes are not configurable through environment variables — set them in config/auth/jwt.yml:
jairouter:
security:
jwt:
expiration-minutes: 15 # access token lifetime
refresh-expiration-days: 30 # refresh token lifetime
Asymmetric Key (RS256/RS384/RS512)¶
# Production Environment Asymmetric Key Configuration
export JWT_PUBLIC_KEY="-----BEGIN PUBLIC KEY-----\nyour-public-key-here\n-----END PUBLIC KEY-----"
export JWT_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\nyour-private-key-here\n-----END PRIVATE KEY-----"
3. Configure User Accounts¶
jairouter:
security:
jwt:
enabled: true
secret: "dev-jwt-secret-key-for-development-only-not-for-production"
algorithm: "HS256"
expiration-minutes: 60
refresh-expiration-days: 7
issuer: "jairouter"
blacklist-enabled: true
# User Account Configuration
accounts:
- username: "admin"
password: "{bcrypt}$2a$10$xmZ5S3DY567m5z6vcPVkreKZ885VqWFb1DB5.RgCEvqHLKj0H/G7u"
roles: [ "ADMIN", "USER" ]
enabled: true
- username: "user"
password: "{noop}user123"
roles: [ "USER" ]
enabled: true
4. Client Usage¶
Add the JWT token in the HTTP request header:
curl -H "Jairouter_Token: your-jwt-token-here" \
-X POST \
-H "Content-Type: application/json" \
-d '{"model": "gpt-3.5-turbo", "messages": [...]}' \
http://localhost:8080/v1/chat/completions
Login to Obtain JWT Token¶
Login Endpoint¶
Request Example¶
curl -X POST http://localhost:8080/api/auth/jwt/login \
-H "Content-Type: application/json" \
-d '{
"username": "admin",
"password": "admin123"
}'
Response Example¶
{
"success": true,
"message": "Login successful",
"data": {
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"tokenType": "Bearer",
"expiresIn": 3600,
"message": "Login successful",
"timestamp": "2023-01-01T12:00:00"
},
"errorCode": null
}
JWT Configuration Parameters¶
| Parameter | Type | Default | Description |
|---|---|---|---|
enabled | boolean | false | Enable JWT authentication |
secret | string | - | JWT signing key (symmetric algorithm) |
public-key | string | - | JWT public key (asymmetric algorithm) |
private-key | string | - | JWT private key (asymmetric algorithm) |
algorithm | string | "HS256" | JWT signing algorithm |
expiration-minutes | int | 60 | Access token expiration (minutes) |
refresh-expiration-days | int | 7 | Refresh token expiration (days) |
issuer | string | "jairouter" | JWT issuer identifier |
blacklist-enabled | boolean | true | Enable blacklist functionality |
jwt-header | string | "Jairouter_Token" | Custom JWT header name |
accounts | array | [] | User account list |
Supported Signing Algorithms¶
Symmetric Algorithms (HMAC)¶
- HS256: HMAC using SHA-256
- HS384: HMAC using SHA-384
- HS512: HMAC using SHA-512
Asymmetric Algorithms (RSA)¶
- RS256: RSASSA-PKCS1-v1_5 using SHA-256
- RS384: RSASSA-PKCS1-v1_5 using SHA-384
- RS512: RSASSA-PKCS1-v1_5 using SHA-512
jairouter:
security:
jwt:
algorithm: "RS256"
public-key: |
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...
-----END PUBLIC KEY-----
private-key: |
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC...
-----END PRIVATE KEY-----
Token Refresh Mechanism¶
Configure Refresh Token¶
jairouter:
security:
jwt:
expiration-minutes: 15 # Access token expires in 15 minutes
refresh-expiration-days: 30 # Refresh token expires in 30 days
Refresh Token Flow¶
Obtain Access Token and Refresh Token
Use Access Token to Access API
Refresh Access Token
JWT Token Persistence¶
Enable Token Persistence¶
jairouter:
security:
jwt:
persistence:
enabled: true # master switch for token persistence
storage-path: config-store # file store used by the default persistence impl
memory:
max-tokens: 50000 # in-memory cache bound
cleanup-threshold: 0.8 # evict when the cache is 80% full
lru-enabled: true
startup-recovery:
enabled: true # reload persisted tokens on boot
composite:
enabled: false # combine file + Redis stores
sync:
enabled: false # background sync between stores
cleanup:
enabled: true
schedule: "0 0 2 * * ?" # daily at 02:00
retention-days: 30
batch-size: 1000
redis:
enabled: false # Redis connection comes from spring.data.redis.*
H2 Database Storage Advantages¶
- Default Storage Method: H2 database is the default storage method for JWT tokens
- Persistence: Data is not lost when the application restarts
- High Performance: Embedded database with no network overhead
- Easy Maintenance: Single database file, easy to backup
- Powerful Queries: Support for complex SQL queries
Blacklist Functionality¶
Enable Blacklist¶
jairouter:
security:
jwt:
blacklist-enabled: true
blacklist:
persistence:
enabled: true
storage-path: config-store/jwt-blacklist
max-memory-size: 10000 # in-memory entries kept before eviction
cleanup-interval: 3600 # seconds between cleanup runs
Token Revocation¶
Behavior When Storage Is Unavailable¶
Blacklist checks depend on the storage backend (Redis). When it is unreachable, checks degrade to the local cache of the current instance:
- Tokens already recorded in the local cache are still blocked;
- Tokens that miss the local cache are allowed — so before the storage recovers, tokens revoked by another instance, or dropped from the local cache by a restart of this instance, no longer take effect immediately; revocation degrades from global and immediate to best-effort;
- The degradation is reported once on the first failure (later failures drop to DEBUG level), so per-request log spam no longer hides real authentication failures;
- A storage availability probe runs at startup and warns explicitly when the backend is unreachable, instead of waiting for the first failing request;
- Checks resume automatically once the storage recovers — no restart required.
⚠️ This is an intentional availability-first trade-off. If your deployment treats immediate revocation as a hard security requirement, keep the blacklist storage available alongside the gateway (same compose file / cluster, with health checks) and watch the startup warning.
Token Management APIs¶
Get Token List¶
curl -X GET "http://localhost:8080/api/auth/jwt/tokens?page=0&size=20&status=ACTIVE" \
-H "Jairouter_Token: admin_token"
Revoke Specific Token¶
curl -X POST "http://localhost:8080/api/auth/jwt/tokens/token-uuid-123/revoke" \
-H "Jairouter_Token: admin_token" \
-H "Content-Type: application/json" \
-d '{"reason": "Security policy violation"}'
Bulk Token Revocation¶
curl -X POST "http://localhost:8080/api/auth/jwt/tokens/revoke-batch" \
-H "Jairouter_Token: admin_token" \
-H "Content-Type: application/json" \
-d '{
"tokenIds": ["token-uuid-123", "token-uuid-456"],
"reason": "Bulk security cleanup"
}'
Get Blacklist Statistics¶
curl -X GET "http://localhost:8080/api/auth/jwt/blacklist/stats" \
-H "Jairouter_Token: admin_token"
Integration with API Key¶
JWT authentication can be used alongside API Key authentication:
Authentication Priority: 1. If the request contains a JWT token, JWT authentication is used first 2. If JWT authentication fails or no JWT token exists, API Key authentication is attempted 3. If both authentication methods fail, a 401 error is returned
Security Best Practices¶
1. Key Management¶
- Use Strong Keys: Symmetric keys should be at least 256 bits (32 bytes)
- Regular Rotation: Regularly rotate JWT signing keys
- Secure Storage: Store keys using environment variables or secret management systems
2. Token Lifecycle¶
- Short-lived Access Tokens: Access tokens should have short expiration times (15-60 minutes)
- Long-lived Refresh Tokens: Refresh tokens can have longer expiration times (7-30 days)
- Timely Revocation: Revoke tokens promptly when users log out
3. Algorithm Selection¶
- Production Recommendation: Use asymmetric algorithms like RS256
- Development: Symmetric algorithms like HS256 can be used
- Avoid Weak Algorithms: Do not use the none algorithm
Troubleshooting¶
Common Issues¶
Token Validation Failed¶
Error: Invalid JWT token
Solutions: 1. Check token format 2. Verify signing key configuration 3. Check if token is expired 4. View detailed error logs
Token Expired¶
Error: JWT token has expired
Solutions: 1. Use refresh token to get new access token 2. Login again to get new token 3. Adjust token expiration configuration
Debug Tips¶
Enable Verbose Logging¶
Token Decoding Tools¶
- https://jwt.io/
- https://jwt-decoder.com/
Last updated: 2026-05-21