This guide covers security best practices, threat model, and production hardening for AuthGate.
- Production Deployment Checklist
- Threat Model
- Secrets Management
- TLS/HTTPS Configuration
- Database Security
- Session Security
- Rate Limiting
- Audit and Compliance
- Incident Response
Before deploying AuthGate to production, complete this security checklist:
- Change
JWT_SECRETto strong random value (32+ characters, useopenssl rand -hex 32) - Change
SESSION_SECRETto strong random value (32+ characters) - Set secure
DEFAULT_ADMIN_PASSWORD(or immediately change auto-generated password) - Never commit secrets to version control
- Use environment variables or secrets management system
- Rotate secrets regularly (JWT_SECRET: every 90 days, SESSION_SECRET: every 180 days)
- Use HTTPS exclusively (set
BASE_URLtohttps://...) - Obtain valid SSL/TLS certificates (Let's Encrypt or commercial CA)
- Configure firewall rules (only expose ports 80, 443)
- Use reverse proxy (Nginx, Caddy) for additional security layers
- Enable HTTP/2 for better performance
- Configure proper CORS policies if needed
- Set appropriate
DeviceCodeExpiration(default: 30 minutes) - Set appropriate
JWTExpiration(default: 1 hour, max: 24 hours) - Set appropriate
REFRESH_TOKEN_EXPIRATION(default: 30 days) - Consider enabling token rotation for high-security scenarios (
ENABLE_TOKEN_ROTATION=true) - Review token scopes and ensure least privilege
- Enable rate limiting (enabled by default)
- Use Redis store for multi-pod deployments (
RATE_LIMIT_STORE=redis) - Adjust limits based on traffic patterns
- Monitor rate limit events in audit logs
- Set up alerts for excessive rate limiting
- Enable audit logging (enabled by default)
- Set appropriate retention period (
AUDIT_LOG_RETENTION, default: 90 days) - Monitor audit log storage growth
- Set up regular exports for compliance (CSV available)
- Review audit logs regularly for security incidents
- Set up alerts for critical audit events
- Use PostgreSQL for production (more secure than SQLite)
- Enable database encryption at rest
- Regularly backup database (automated daily backups)
- Restrict database access (localhost only or private network)
- Use strong database passwords
- Enable database SSL/TLS connections
- Run as non-root user (Docker: UID 1000, Systemd: dedicated user)
- Use Docker non-root user mode (already configured in Dockerfile)
- Configure timeouts (ReadTimeout, WriteTimeout, IdleTimeout)
- Set up automated cleanup for expired tokens and device codes
- Implement secure session management (7-day expiry, encrypted cookies)
- Enable CSRF protection (already enabled)
- Monitor
/healthendpoint for service availability - Set up log aggregation (Loki, Papertrail, CloudWatch)
- Configure alerts for critical errors
- Monitor failed login attempts
- Track unusual authentication patterns
- Set up automated backup verification
- Educate users to use
/account/sessionsto review active devices - Provide clear instructions for revoking suspicious sessions
- Document incident response procedures
- Train administrators on security best practices
✅ Client Secret Exposure in Distributed Apps
- Device Authorization Flow doesn't require embedding secrets in CLI tools
- Device codes are short-lived (30 minutes) and single-use
✅ Phishing Attacks
- User authorizes on trusted domain (your AuthGate instance)
- Device codes displayed in CLI, not entered by user
- Verification URI clearly shows your domain
✅ Replay Attacks
- Device codes are single-use (marked as used after authorization)
- JWTs have expiration times and signature verification
- CSRF tokens protect state-changing operations
✅ Token Tampering
- JWTs signed with HMAC-SHA256 (or external provider)
- Signature verification on every request
- Token claims cannot be modified without detection
✅ Brute Force Attacks
- Rate limiting enabled by default (configurable per endpoint)
- IP-based tracking prevents single attacker from overwhelming service
- Failed login attempts logged in audit trail
✅ API Abuse and DoS Attempts
- Per-endpoint rate limits protect critical paths
- Memory or Redis store for distributed rate limiting
- Graceful degradation when limits are exceeded
✅ Session Hijacking
- Encrypted session cookies (AES-256)
- HttpOnly and Secure flags on cookies
- Session fingerprinting support (configurable)
- 7-day session expiration (configurable)
🔒 Server Host Security
- OS hardening and security updates
- Firewall configuration
- SSH key management
- Intrusion detection system (IDS)
🔒 Database Encryption at Rest
- Use encrypted volumes (LUKS, AWS EBS encryption)
- Secure database backups (encrypted storage)
- Restrict database file permissions (0600)
🔒 TLS/HTTPS in Production
- Valid SSL certificates (not self-signed)
- Strong cipher suites (TLSv1.2+)
- HSTS headers (Strict-Transport-Security)
🔒 Secret Rotation Policies
- Regular rotation of JWT_SECRET (every 90 days)
- Session secret rotation (every 180 days)
- Admin password changes (every 90 days)
- OAuth client secret rotation (as needed)
🔒 Network Isolation
- Place database on private network
- Restrict external access to application port only
- Use VPN for administrative access
# Generate 256-bit secrets
openssl rand -hex 32
# Or use /dev/urandom
head -c 32 /dev/urandom | base64Option 1: Environment Variables (Docker, Systemd)
# .env file (set permissions to 0600)
JWT_SECRET=abc123...
SESSION_SECRET=def456...
# Restrict permissions
chmod 600 .env
chown authgate:authgate .envOption 2: Secrets Management Systems
HashiCorp Vault:
# Store secret
vault kv put secret/authgate JWT_SECRET=abc123...
# Retrieve in startup script
export JWT_SECRET=$(vault kv get -field=JWT_SECRET secret/authgate)AWS Secrets Manager:
# Store secret
aws secretsmanager create-secret --name authgate-jwt-secret --secret-string "abc123..."
# Retrieve in application
aws secretsmanager get-secret-value --secret-id authgate-jwt-secretKubernetes Secrets:
apiVersion: v1
kind: Secret
metadata:
name: authgate-secrets
type: Opaque
data:
jwt-secret: YWJjMTIzLi4u # base64 encoded
session-secret: ZGVmNDU2Li4uRotating JWT_SECRET:
- Generate new secret:
openssl rand -hex 32 - Schedule maintenance window (brief service interruption)
- Update
JWT_SECRETin configuration - Restart service
- All existing tokens become invalid (users must re-authenticate)
- Consider implementing dual-key verification during rotation
Rotating SESSION_SECRET:
- Generate new secret
- Update
SESSION_SECRETin configuration - Restart service
- All existing sessions become invalid (users must re-login)
# Install Certbot
sudo apt-get install certbot python3-certbot-nginx
# Obtain certificate
sudo certbot --nginx -d auth.yourdomain.com
# Auto-renewal (configured automatically)
sudo certbot renew --dry-runserver {
listen 443 ssl http2;
server_name auth.yourdomain.com;
# SSL Configuration
ssl_certificate /etc/letsencrypt/live/auth.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/auth.yourdomain.com/privkey.pem;
# Modern SSL configuration (Mozilla SSL Configuration Generator)
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
# HSTS (15768000 seconds = 6 months)
add_header Strict-Transport-Security "max-age=15768000; includeSubDomains" always;
# Additional security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
# ... proxy configuration
}# Test with SSL Labs
# Visit: https://www.ssllabs.com/ssltest/analyze.html?d=auth.yourdomain.com
# Test locally
openssl s_client -connect auth.yourdomain.com:443 -tls1_2# Set proper file permissions
chmod 600 oauth.db
chown authgate:authgate oauth.db
# Enable WAL mode for better concurrency
sqlite3 oauth.db "PRAGMA journal_mode=WAL;"
# Regular backups
sqlite3 oauth.db ".backup /backup/oauth-$(date +%Y%m%d).db"Connection Security:
# Use SSL connections (postgresql.conf)
ssl = on
ssl_cert_file = '/path/to/server.crt'
ssl_key_file = '/path/to/server.key'
# Require SSL for connections (pg_hba.conf)
hostssl all all 0.0.0.0/0 md5Database Hardening:
-- Create dedicated user
CREATE USER authgate WITH PASSWORD 'strong-password';
-- Grant minimal permissions
GRANT CONNECT ON DATABASE authgate TO authgate;
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO authgate;
-- Revoke public schema access
REVOKE ALL ON SCHEMA public FROM PUBLIC;Encryption at Rest:
# Enable transparent data encryption (TDE)
# Implementation varies by PostgreSQL version and platform
# Consult PostgreSQL documentation for your version# Session settings in config/config.go
SessionSecret: os.Getenv("SESSION_SECRET")
SessionMaxAge: 7 * 24 * 60 * 60 # 7 days
SessionSecure: true # HTTPS only
SessionHttpOnly: true # Prevent XSS
SessionSameSite: "Lax" # CSRF protectionEnable session fingerprinting to detect session hijacking:
# .env
ENABLE_SESSION_FINGERPRINTING=trueThis creates a fingerprint from:
- User-Agent header
- IP address (optional)
- Accept-Language header
Configure automatic session termination after inactivity:
# .env
SESSION_IDLE_TIMEOUT=1h # Terminate after 1 hour of inactivitySee Configuration Guide - Rate Limiting for complete documentation.
- Prevents password brute force (5 req/min on /login)
- Mitigates device code enumeration (10 req/min on /oauth/device/code)
- Prevents user code guessing (10 req/min on /device/verify)
- Protects against DoS (configurable limits per endpoint)
- Per-IP tracking (prevents single attacker from overwhelming service)
# .env
ENABLE_RATE_LIMIT=true
RATE_LIMIT_STORE=redis # For multi-pod deployments
REDIS_ADDR=redis-service:6379
REDIS_PASSWORD=secure-password
# Adjust limits based on your traffic
LOGIN_RATE_LIMIT=5
DEVICE_CODE_RATE_LIMIT=10
TOKEN_RATE_LIMIT=20
DEVICE_VERIFY_RATE_LIMIT=10# .env
ENABLE_AUDIT_LOGGING=true
AUDIT_LOG_RETENTION=2160h # 90 days (adjust for compliance)SOC 2:
- Audit all authentication events
- Track all token operations
- Monitor failed login attempts
- Export audit logs regularly
ISO 27001:
- Retain audit logs for required period (90 days minimum)
- Implement automated cleanup
- Protect audit logs from tampering
GDPR:
- Log data access events
- Track consent (if applicable)
- Provide audit trail for data subject requests
- Implement data retention policies
- Weekly: Review failed authentication attempts
- Monthly: Analyze rate limit events and suspicious patterns
- Quarterly: Export audit logs for compliance reporting
- Annually: Full security audit and penetration testing
Step 1: Detection
- Monitor for critical audit events
- Review failed authentication patterns
- Check rate limit exceeded alerts
- Analyze unusual traffic patterns
Step 2: Containment
# Immediately revoke all tokens for affected user
curl -X POST https://auth.yourdomain.com/account/sessions/revoke-all \
-H "Cookie: session=..."
# Block attacker IP at firewall level
sudo iptables -A INPUT -s <attacker-ip> -j DROP
# Temporarily disable affected OAuth client
# (Update database or use admin interface)Step 3: Investigation
# Export audit logs for analysis
curl "https://auth.yourdomain.com/admin/audit/export?since=24h" \
-H "Cookie: admin-session=..." -o incident-logs.csv
# Review systemd logs
sudo journalctl -u authgate --since "24 hours ago" > authgate-incident.log
# Check database for anomalies
sqlite3 oauth.db "SELECT * FROM audit_logs WHERE severity='CRITICAL' AND event_time > datetime('now', '-24 hours');"Step 4: Remediation
- Rotate affected secrets (JWT_SECRET, SESSION_SECRET)
- Force password reset for affected users
- Patch vulnerabilities if applicable
- Update firewall rules
- Review and update rate limits
Step 5: Recovery
- Restore from backup if data was compromised
- Re-enable affected services
- Communicate with affected users
- Document incident in incident report
Step 6: Post-Incident Review
- Analyze root cause
- Update security procedures
- Implement additional controls
- Schedule follow-up review
Maintain an up-to-date incident response contact list:
- Security Team: security@yourdomain.com
- On-Call Engineer: [phone number]
- Platform Provider: [support contact]
- Legal/Compliance: [contact info]
- OWASP Top 10
- CWE/SANS Top 25
- NIST Cybersecurity Framework
- RFC 8628 - OAuth 2.0 Device Authorization Grant
- RFC 8725 - JWT Best Current Practices
Next Steps:
- Deployment Guide - Production deployment
- Monitoring Guide - Set up monitoring and alerts
- Troubleshooting - Debug security issues