This document outlines the required security configurations for deploying the OAuth2 server.
The server will issue a WARNING on startup if JWT secret is not properly configured:
# Generate a secure random secret (minimum 32 characters)
export OAUTH2_JWT_SECRET=$(openssl rand -hex 32)Important:
- The server uses a fail-safe default for testing:
insecure-default-for-testing-only-change-in-production - This default triggers a validation warning on startup
- NEVER use the default in production!
- The validation requires secrets to be at least 32 characters
- Set
OAUTH2_JWT_SECRETenvironment variable before running the server
Why this is required:
- JWT tokens are signed with this secret
- Weak or default secrets compromise the entire authentication system
- The server validates the configuration and logs warnings if defaults are detected
For production deployments, set a persistent session key to maintain sessions across server restarts:
# Generate a 64-byte (128 hex character) session key
export OAUTH2_SESSION_KEY=$(openssl rand -hex 64)Why this is important:
- Without this, a random key is generated on each startup
- Users will be logged out when the server restarts
- Sessions won't work properly in multi-instance deployments
Update default database credentials before production:
-- V5__insert_default_data.sql contains INSECURE defaults
-- Generate secure credentials:
openssl rand -hex 32 # For client secretsAction items:
- Remove or regenerate the default client credentials in the migration
- Generate proper Argon2 password hashes for test users
- Consider removing V5__insert_default_data.sql entirely in production
The server uses constant-time comparison for client secrets to prevent timing attacks:
use subtle::ConstantTimeEq;
let secret_match = client.client_secret.as_bytes()
.ct_eq(msg.client_secret.as_bytes())
.into();DO NOT store access tokens in localStorage (XSS vulnerability). The application uses:
- httpOnly cookies for session management
- Server-side token storage
- Secure cookie flags in production
PKCE (RFC 7636) is implemented using S256 challenge method:
- Prevents authorization code interception attacks
- Required for public clients
- Recommended for all clients
The migration script uses a pinned Docker image digest to prevent supply chain attacks:
FLYWAY_IMAGE="flyway/flyway:10-alpine@sha256:..."Update process:
- Review Flyway release notes
- Test migrations in staging
- Update the digest in scripts/migrate.sh
- Document the change in git commit
Before deploying to production:
- Set
OAUTH2_JWT_SECRET(minimum 32 characters) - Set
OAUTH2_SESSION_KEY(128 hex characters) - Remove or secure default credentials in V5__insert_default_data.sql
- Enable HTTPS (configure reverse proxy)
- Set up proper database with authentication
- Configure CORS appropriately for your domains
- Review and update redirect URIs for OAuth clients
- Set up rate limiting (see TODO.md)
- Enable audit logging
- Configure monitoring and alerting
- Rotate secrets regularly (implement key rotation)
oauth2_server_oauth_failed_authentications # Failed login attempts
oauth2_server_oauth_token_revoked_total # Revoked tokens
oauth2_server_http_requests_total # Request patterns
Watch for:
- Multiple failed authentication attempts from same IP
- Unusual token issuance patterns
- Invalid client credential attempts
- Suspicious redirect URIs
If credentials are compromised:
-
Immediately:
- Rotate
OAUTH2_JWT_SECRET - Rotate
OAUTH2_SESSION_KEY - Revoke all active tokens
- Review audit logs
- Rotate
-
Within 24 hours:
- Notify affected users
- Rotate client secrets
- Update documentation
- Implement additional monitoring
-
Post-incident:
- Conduct security review
- Update security procedures
- Consider implementing 2FA (see TODO.md)
Status: No fix available
Severity: Medium (5.9)
Affected: rsa 0.9.9 (transitive dependency via sqlx-mysql)
Description: Marvin Attack - potential key recovery through timing sidechannels
Last Updated: 2025-12-26
Mitigation:
- This is a transitive dependency from sqlx-mysql via sqlx-macros
- The server primarily uses SQLite and PostgreSQL, not MySQL
- The mysql feature is pulled in by sqlx's "macros" feature which requires "any" database support
- The vulnerability affects RSA PKCS#1 v1.5 decryption operations
- This server does not use RSA encryption/decryption operations in its code
- Monitor for updates to sqlx or rsa that include a patched version
The following vulnerabilities have been resolved through dependency updates:
-
proc-macro-error (RUSTSEC-2024-0370) - RESOLVED ✅
- Fixed by updating utoipa from 4.x to 5.4
- Status: No longer a transitive dependency
-
rustls-pemfile (RUSTSEC-2025-0134) - RESOLVED ✅
- Fixed by updating reqwest from 0.11 to 0.12 and oauth2 from 4.4 to 5.0
- Status: Now using maintained version via updated dependencies
-
yaml-rust (RUSTSEC-2024-0320) - RESOLVED ✅
- Fixed by updating config from 0.13 to 0.15
- Status: config 0.15 no longer depends on yaml-rust
Action: Run cargo audit regularly and update dependencies when patches become available.