Before deploying FrontMCP authentication to production, review this comprehensive checklist covering security, configuration, and operational requirements.
Pre-Deployment Checklist
Configure Persistent Token Storage
Replace in-memory storage with Redis or another persistent store. auth : {
mode : ' orchestrated ' ,
type : ' local ' ,
tokenStorage : {
type : ' redis ' ,
config : {
host : process . env . REDIS_HOST !,
port : parseInt ( process . env . REDIS_PORT || ' 6379 ' ),
password : process . env . REDIS_PASSWORD ,
tls : true ,
},
},
}
Provide Persistent Signing Keys
Auto-generated keys are lost on restart. Provide stable keys. auth : {
local : {
signKey : JSON . parse ( process . env . JWT_SIGNING_KEY ),
},
}
Configure Token Lifetimes
Set appropriate token expiration based on security requirements. auth : {
refresh : {
accessTokenTtl : 900 , // 15 minutes
refreshTokenTtl : 604800 , // 7 days
rotateRefreshToken : true ,
},
}
Enable HTTPS
All production traffic must use TLS. Configure your reverse proxy or load balancer.
Set Expected Audience
For transparent mode, always validate the audience claim. auth : {
mode : ' transparent ' ,
expectedAudience : ' https://api.yourservice.com ' ,
}
Security Requirements
Required
HTTPS only - Never expose auth endpoints over HTTP in production
Persistent token storage - Redis with TLS for multi-instance deployments
Stable signing keys - Provide keys via environment or secrets manager
PKCE enforcement - OAuth 2.1 requires PKCE (S256 only)
Refresh token rotation - Always rotate refresh tokens on use
Audience validation - Validate aud claim in transparent mode
Recommended
Rate limiting - Protect token endpoints from brute force
Monitoring - Alert on auth failures, unusual patterns
Key rotation - Rotate signing keys periodically (30-90 days)
Scope minimization - Request only necessary scopes
Consent UI - Let users see what they’re authorizing
Configuration Reference
Minimum Production Configuration
import { FrontMcp } from ' @frontmcp/sdk ' ;
@ FrontMcp ({
info : { name : ' ProductionServer ' , version : ' 1.0.0 ' },
auth : {
mode : ' orchestrated ' ,
type : ' local ' ,
sessionMode : ' stateful ' ,
// Persistent storage
tokenStorage : {
type : ' redis ' ,
config : {
host : process . env . REDIS_HOST !,
port : parseInt ( process . env . REDIS_PORT || ' 6379 ' ),
password : process . env . REDIS_PASSWORD ,
tls : true ,
keyPrefix : ' auth: ' ,
},
},
// Stable keys
local : {
signKey : JSON . parse ( process . env . JWT_SIGNING_KEY !),
},
// Token refresh settings
refresh : {
enabled : true ,
skewSeconds : 60 ,
},
// Security
consent : { enabled : true },
},
})
export class Server {}
Environment Variables
# Required for Redis
REDIS_HOST = redis.example.com
REDIS_PORT = 6379
REDIS_PASSWORD = your-redis-password
# Required for token signing
JWT_SIGNING_KEY = ' {"kty":"RSA","kid":"prod-key-1",...} '
# For remote/transparent mode
IDP_PROVIDER_URL = https://auth.example.com
IDP_CLIENT_ID = your-client-id
IDP_CLIENT_SECRET = your-client-secret
IDP_EXPECTED_AUDIENCE = https://api.yourservice.com
Token Lifetime Guidelines
Environment Access Token Refresh Token Rationale Development 1 hour 7 days Developer convenience Staging 30 min 7 days Balance testing/security Production 15 min 7-30 days Security with usability High Security 5 min 1 day Minimize exposure window
Shorter access tokens improve security but increase refresh frequency. Monitor your refresh token endpoint load.
Key Management
Generating Production Keys
# Generate RS256 key pair
openssl genrsa -out private.pem 2048
openssl rsa -in private.pem -pubout -out public.pem
# Convert to JWK format (use a tool like step-cli)
step crypto jwk create --kty RSA --use sig --alg RS256 \
public.jwk private.jwk
Key Rotation Strategy
Configuration for Key Rotation
auth : {
local : {
signKey : currentKey ,
keyRotationDays : 30 ,
maxKeys : 3 , // Keep old keys for validation during rotation
},
}
Redis Configuration
Secure Redis Connection
tokenStorage : {
type : ' redis ' ,
config : {
host : ' redis.example.com ' ,
port : 6379 ,
password : process . env . REDIS_PASSWORD ,
tls : true ,
keyPrefix : ' frontmcp:auth: ' ,
},
}
Redis Data Stored
Key Pattern Data TTL {prefix}pending:{id}Pending authorization 10 min {prefix}code:{code}Authorization code 60 sec {prefix}refresh:{token}Refresh token 7-30 days {prefix}session:{id}Session data Configurable {prefix}vault:{session}Token vault Session TTL
Monitoring & Alerting
Key Metrics to Monitor
Metric Alert Threshold Description Auth failures/min > 100 Possible brute force Token refresh rate > 10x normal Possible token theft JWKS fetch errors Any IdP connectivity issue Redis connection errors Any Storage unavailable Token issuance latency > 500ms Performance degradation
Logging Configuration
import { FrontMcp , LogLevel } from ' @frontmcp/sdk ' ;
@ FrontMcp ({
info : { name : ' Server ' , version : ' 1.0.0 ' },
logging : {
level : LogLevel . INFO ,
// Don't log tokens or secrets
redact : [ ' access_token ' , ' refresh_token ' , ' client_secret ' ],
},
})
export class Server {}
Common Production Issues
Tokens invalid after deployment
Cause: Auto-generated keys changed after restart.Solution: Provide persistent signing keys via environment variable:local : {
signKey : JSON . parse ( process . env . JWT_SIGNING_KEY !),
}
Session not found errors across instances
Cause: Using in-memory storage with multiple instances.Solution: Configure shared Redis storage:tokenStorage : {
type : ' redis ' ,
config : {
host : process . env . REDIS_HOST !,
port : parseInt ( process . env . REDIS_PORT || ' 6379 ' ),
password : process . env . REDIS_PASSWORD ,
},
}
JWKS fetch fails intermittently
Cause: Network issues or IdP rate limiting.Solution:
Increase JWKS cache TTL
Consider inline JWKS for critical IdPs
Add retry logic with exponential backoff
High latency on token endpoint
Cause: Redis connection issues or key generation overhead.Solution:
Use Redis connection pooling
Pre-generate signing keys (don’t generate on-demand)
Monitor Redis latency
Security Hardening
Disable Insecure Options
auth : {
mode : ' orchestrated ' ,
type : ' local ' ,
// Production settings
allowDefaultPublic : false , // No anonymous access
dcrEnabled : false , // Disable DCR in production
// Use orchestrated mode login page or remote IdP
// Never use the demo login page in production
}
Configure your reverse proxy to add security headers:
# Example nginx configuration
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always ;
add_header X-Content-Type-Options "nosniff" always ;
add_header X-Frame-Options "DENY" always ;
add_header Content-Security-Policy "default-src 'self'" always ;
Rate Limiting
# Rate limit token endpoint
location /oauth/token {
limit_req zone=token_limit burst=10 nodelay ;
proxy_pass http://backend ;
}
Deployment Patterns
Single Instance
Multi-Instance
Stateless
// Simple deployment - in-memory works but not recommended
auth : {
tokenStorage : { type : ' memory ' }, // Data lost on restart
}
In-memory storage loses all sessions on restart. Users must re-authenticate.
// Required for horizontal scaling
auth : {
sessionMode : ' stateful ' ,
tokenStorage : {
type : ' redis ' ,
config : {
host : process . env . REDIS_HOST !,
port : parseInt ( process . env . REDIS_PORT || ' 6379 ' ),
password : process . env . REDIS_PASSWORD ,
},
},
}
All instances must share the same Redis and signing keys. // No shared state needed - tokens contain all info
auth : {
sessionMode : ' stateless ' ,
local : {
signKey : JSON . parse ( process . env . JWT_SIGNING_KEY !),
},
}
Simpler architecture but larger tokens, no silent refresh.
Quick Reference
OAuth 2.1 Compliance Checklist
PKCE required for all clients (S256 only)
Refresh token rotation enabled
Authorization codes single-use
Pre-Production Verification
# Test token endpoint
curl -X POST https://your-server/oauth/token \
-d " grant_type=authorization_code " \
-d " code=test-code " \
-d " client_id=your-client " \
-d " code_verifier=verifier "
# Verify JWKS endpoint
curl https://your-server/.well-known/jwks.json
# Check server metadata
curl https://your-server/.well-known/oauth-authorization-server
Next Steps