JWT Authentication Configuration Guide¶
Document Version: 1.0.0
Last Updated: 2025-08-19
Git Commit:
Author:
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
Quick Start¶
1. Enable JWT Authentication¶
jairouter:
security:
enabled: true
jwt:
enabled: true
secret: "${JWT_SECRET}"
algorithm: "HS256"
expiration-minutes: 60
Configuration Explanation
To change the HTTP header used to carry the JWT, you can add the following when enabling JWT:
Authorization
header but will instead read the custom Jairouter_Token
header to obtain the token. This is suitable for scenarios where the Authorization
header is shared with existing systems.2. Set JWT Key¶
Symmetric Key (HS256/HS384/HS512)¶
# Production Environment JWT Key Configuration
export PROD_JWT_SECRET="your-very-strong-production-jwt-secret-key-at-least-32-characters-long"
Symmetric Key (HS256/HS384/HS512)¶
# Production Environment JWT Key Configuration
export PROD_JWT_SECRET="your-very-strong-production-jwt-secret-key-at-least-32-characters-long"
# Optional Expiration Time Configuration
export PROD_JWT_EXPIRATION_MINUTES=15
export PROD_JWT_REFRESH_EXPIRATION_DAYS=30
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" # BCrypt encrypted password
roles: [ "ADMIN", "USER" ]
enabled: true
- username: "user"
password: "{noop}user123" # Plain text password for development, encrypted in production
roles: [ "USER" ]
enabled: true
4. Client Usage¶
Add the JWT token in the HTTP request header:
curl -H "Authorization: Bearer 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
}
Error Response¶
{
"success": false,
"message": "Login failed: Incorrect username or password",
"data": null,
"errorCode": "LOGIN_FAILED"
}
Detailed Configuration¶
JWT Configuration Parameters¶
Parameter | Type | Default | Description |
---|---|---|---|
enabled | boolean | false | Whether to 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 time (minutes) |
refresh-expiration-days | int | 7 | Refresh token expiration time (days) |
issuer | string | "jairouter" | JWT issuer identifier |
blacklist-enabled | boolean | true | Whether to enable blacklist functionality |
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-----
JWT Token Format¶
Standard Claims¶
JAiRouter supports the following standard JWT claims:
{
"iss": "jairouter", // Issuer
"sub": "user123", // Subject (User ID)
"aud": "jairouter-api", // Audience
"exp": 1640995200, // Expiration Time
"iat": 1640991600, // Issued At
"nbf": 1640991600, // Not Before
"jti": "unique-token-id" // JWT ID
}
Custom Claims¶
You can include custom claims in the JWT:
{
"sub": "user123",
"permissions": ["read", "write"],
"department": "IT",
"role": "admin",
"custom_data": {
"user_level": "premium",
"features": ["feature1", "feature2"]
}
}
Password Encryption Configuration¶
JAiRouter supports multiple password encryption methods to enhance security:
BCrypt Encryption Configuration¶
BCrypt is a secure password hashing function recommended for production environments:
// Example code: Generate BCrypt encrypted password
String rawPassword = "admin123";
org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder encoder =
new org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder();
String encodedPassword = encoder.encode(rawPassword);
System.out.println("Encoded password: " + encodedPassword);
Using BCrypt encrypted password in configuration file:
jairouter:
security:
jwt:
accounts:
- username: "admin"
password: "{bcrypt}$2a$10$xmZ5S3DY567m5z6vcPVkreKZ885VqWFb1DB5.RgCEvqHLKj0H/G7u"
roles: [ "ADMIN", "USER" ]
enabled: true
Plain Text Password Configuration (Development Only)¶
For convenience in development and testing, plain text password configuration is supported:
jairouter:
security:
jwt:
accounts:
- username: "user"
password: "{noop}user123"
roles: [ "USER" ]
enabled: true
Password Encoder Configuration¶
Configure password encoder in SecurityConfiguration.java:
/**
* Configure password encoder - BCrypt as default encoder
*/
@Bean
public PasswordEncoder passwordEncoder() {
java.util.Map<String, org.springframework.security.crypto.password.PasswordEncoder> encoders =
java.util.Map.of(
"bcrypt", new org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder(10),
"noop", org.springframework.security.crypto.password.NoOpPasswordEncoder.getInstance()
);
org.springframework.security.crypto.password.DelegatingPasswordEncoder delegatingEncoder =
new org.springframework.security.crypto.password.DelegatingPasswordEncoder("bcrypt", encoders);
// Set default password encoder
delegatingEncoder.setDefaultPasswordEncoderForMatches(encoders.get("bcrypt"));
return delegatingEncoder;
}
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-endpoint: "/auth/refresh"
Refresh Token Flow¶
- Obtain Access Token and Refresh Token
Response:
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"expires_in": 900,
"token_type": "Bearer"
}
Use Access Token to Access API
Refresh Access Token
Blacklist Functionality¶
Enable Blacklist¶
jairouter:
security:
jwt:
blacklist-enabled: true
blacklist-cache:
expiration-seconds: 86400 # 24 hours
max-size: 10000 # Maximum cache entries
Token Revocation¶
Revoke token (logout):
Bulk Revocation¶
Revoke all tokens for a user:
curl -X POST http://localhost:8080/auth/revoke-all \
-H "Authorization: Bearer admin_token" \
-H "Content-Type: application/json" \
-d '{"user_id": "user123"}'
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
Performance Optimization¶
Cache Configuration¶
jairouter:
security:
performance:
cache:
redis:
enabled: true
local:
jwt-blacklist:
max-size: 10000
expire-after-write: 86400
Asynchronous Validation¶
jairouter:
security:
performance:
authentication:
async-enabled: true
thread-pool-size: 10
timeout-ms: 5000
Monitoring and Auditing¶
Audit Events¶
jairouter:
security:
audit:
enabled: true
event-types:
jwt-token-issued: true
jwt-token-refreshed: true
jwt-token-revoked: true
jwt-token-expired: true
jwt-validation-failed: true
Monitoring Metrics¶
jairouter_security_jwt_tokens_issued_total
: Total tokens issuedjairouter_security_jwt_tokens_refreshed_total
: Total tokens refreshedjairouter_security_jwt_tokens_revoked_total
: Total tokens revokedjairouter_security_jwt_validation_duration_seconds
: Token validation duration
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
- Key Separation: Use different keys for different environments
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 or anomalies are detected
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
4. Claim Validation¶
- Validate Standard Claims: Always validate standard claims like exp, iat, nbf
- Validate Custom Claims: Validate custom claims based on business requirements
- Principle of Least Privilege: Only include necessary information in tokens
Troubleshooting¶
Common Issues¶
1. Token Validation Failure¶
Error Message: Invalid JWT token
Possible Causes: - Incorrect token format - Signature validation failure - Expired token - Incorrect key configuration
Solutions: 1. Check if token format is correct 2. Verify signature key configuration 3. Check if token has expired 4. Review detailed error logs
2. Token Expired¶
Error Message: JWT token has expired
Solutions: 1. Use refresh token to obtain new access token 2. Re-login to obtain new token 3. Adjust token expiration time configuration
3. Blacklist Issues¶
Error Message: JWT token has been revoked
Solutions: 1. Check if token has been revoked 2. Re-login to obtain new token 3. Check blacklist cache configuration
Debugging Tips¶
1. Enable Detailed Logging¶
2. Token Decoding Tools¶
Use online tools to decode JWT tokens: - https://jwt.io/ - https://jwt-decoder.com/
3. Verify Token Content¶
# Decode JWT token (without signature verification)
echo "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." | base64 -d
Example Configurations¶
Development Environment¶
jairouter:
security:
enabled: true
jwt:
enabled: true
secret: "dev-jwt-secret-key-for-development-only"
algorithm: "HS256"
expiration-minutes: 60
refresh-expiration-days: 1
issuer: "jairouter-dev"
blacklist-enabled: true
accounts:
- username: "admin"
password: "{noop}admin123"
roles: [ "ADMIN", "USER" ]
enabled: true
- username: "user"
password: "{noop}user123"
roles: [ "USER" ]
enabled: true
Production Environment¶
jairouter:
security:
enabled: true
jwt:
enabled: true
algorithm: "RS256"
public-key: "${JWT_PUBLIC_KEY}"
private-key: "${JWT_PRIVATE_KEY}"
expiration-minutes: 15
refresh-expiration-days: 30
issuer: "jairouter-prod"
blacklist-enabled: true
blacklist-cache:
expiration-seconds: 86400
max-size: 50000
accounts:
- username: "admin"
password: "{bcrypt}$2a$10$xmZ5S3DY567m5z6vcPVkreKZ885VqWFb1DB5.RgCEvqHLKj0H/G7u"
roles: [ "ADMIN", "USER" ]
enabled: true
High Availability Environment¶
jairouter:
security:
jwt:
enabled: true
algorithm: "RS256"
public-key: "${JWT_PUBLIC_KEY}"
expiration-minutes: 15
performance:
cache:
redis:
enabled: true
host: "${REDIS_HOST}"
port: "${REDIS_PORT}"
password: "${REDIS_PASSWORD}"
cluster:
enabled: true
nodes:
- "${REDIS_NODE1}"
- "${REDIS_NODE2}"
- "${REDIS_NODE3}"