Skip to main content
Follow these security best practices to harden your Ory Kratos deployment for production use.

Production checklist

Before going to production, verify these security settings:
1

Never use --dev flag

The --dev flag disables critical security features:
# ❌ NEVER in production
kratos serve --dev

# ✅ Production
kratos serve -c /etc/kratos/config.yml
The --dev flag disables CSRF protection, uses insecure cookies, and enables other development-only features.
2

Use HTTPS everywhere

Always use HTTPS for all Kratos endpoints:
serve:
  public:
    base_url: https://auth.example.com/  # ✅
    # NOT http://auth.example.com/  ❌
  admin:
    base_url: https://admin.example.com/  # ✅
3

Generate strong secrets

Use cryptographically secure random secrets (32+ characters):
openssl rand -base64 32
secrets:
  cookie:
    - $(openssl rand -base64 32)
  cipher:
    - $(openssl rand -base64 32)
4

Enable secure cookies

cookies:
  domain: example.com
  path: /
  same_site: Lax  # or Strict
  secure: true  # Required for HTTPS
5

Configure CORS properly

Only allow trusted origins:
serve:
  public:
    cors:
      enabled: true
      allowed_origins:
        - https://example.com
        # Never use "*" in production ❌
      allow_credentials: true
6

Use database SSL/TLS

Always encrypt database connections:
dsn: postgres://user:pass@host/db?sslmode=require
# NOT sslmode=disable ❌
7

Protect admin API

Never expose the admin API publicly. Use:
  • Internal network only
  • API gateway with authentication
  • VPN access
  • IP allowlisting

Password security

Password policies

Enforce strong password requirements:
selfservice:
  methods:
    password:
      enabled: true
      config:
        min_password_length: 12
        identifier_similarity_check_enabled: true
        haveibeenpwned_enabled: true
        max_breaches: 0
min_password_length
number
Minimum password length. Recommended: 12 or higher.
haveibeenpwned_enabled
boolean
Check passwords against HaveIBeenPwned breach database. Always enable in production.
identifier_similarity_check_enabled
boolean
Prevent passwords similar to email/username. Recommended: true.

Password hashing

Use Argon2id for new installations:
hashers:
  algorithm: argon2
  argon2:
    memory: 131072      # 128 MB
    iterations: 3
    parallelism: 4
    salt_length: 16
    key_length: 32
For bcrypt (legacy):
hashers:
  algorithm: bcrypt
  bcrypt:
    cost: 12  # Minimum recommended

Session security

Session lifetime

Set appropriate session lifetimes:
session:
  lifespan: 24h  # Adjust based on security requirements
  earliest_possible_extend: 1h
  cookie:
    persistent: true
    same_site: Lax
Shorter session lifetimes improve security but reduce user convenience. Balance based on your risk profile.

Privileged sessions

Require re-authentication for sensitive operations:
selfservice:
  flows:
    settings:
      privileged_session_max_age: 15m
      required_aal: highest_available

Multi-factor authentication

Enforce MFA

Require MFA for all users or specific operations:
session:
  whoami:
    required_aal: aal2  # Require MFA

selfservice:
  flows:
    login:
      after:
        default_browser_return_url: https://example.com/
        hooks:
          - hook: require_verified_address

Available MFA methods

Enable multiple MFA options:
selfservice:
  methods:
    totp:
      enabled: true
      config:
        issuer: MyApp
    
    webauthn:
      enabled: true
      config:
        rp:
          display_name: MyApp
          id: example.com
          origins:
            - https://example.com
        passwordless: false  # Use as second factor
    
    lookup_secret:
      enabled: true

Network security

Rate limiting

Kratos includes built-in rate limiting. Configure your reverse proxy for additional protection:
# Nginx example
http {
    limit_req_zone $binary_remote_addr zone=kratos_public:10m rate=10r/s;
    limit_req_zone $binary_remote_addr zone=kratos_admin:10m rate=5r/s;
    
    server {
        location / {
            limit_req zone=kratos_public burst=20 nodelay;
            proxy_pass http://kratos:4433;
        }
    }
}

DDoS protection

Use a CDN or DDoS protection service:
  • Cloudflare
  • AWS Shield
  • Google Cloud Armor

Firewall rules

# Allow only necessary ports
iptables -A INPUT -p tcp --dport 4433 -j ACCEPT  # Public API
iptables -A INPUT -p tcp --dport 4434 -j DROP    # Block admin from internet

Email security

SMTP security

Use encrypted SMTP connections:
courier:
  smtp:
    connection_uri: smtps://user:[email protected]:465/
    # Use smtps:// for SSL/TLS
    # Or smtp://...?starttls=true for STARTTLS
    from_address: [email protected]

SPF, DKIM, DMARC

Configure email authentication:
# SPF record
example.com. IN TXT "v=spf1 include:_spf.google.com ~all"

# DKIM record
default._domainkey.example.com. IN TXT "v=DKIM1; k=rsa; p=MIGfMA..."

# DMARC record
_dmarc.example.com. IN TXT "v=DMARC1; p=quarantine; rua=mailto:[email protected]"

Secrets management

Never commit secrets to version control.

Use secret managers

apiVersion: v1
kind: Secret
metadata:
  name: kratos-secrets
type: Opaque
stringData:
  dsn: postgres://user:pass@host/db
  secrets-cookie: your-32-char-secret
  secrets-cipher: your-32-char-secret

Secret rotation

Rotate secrets regularly:
secrets:
  cookie:
    - new-secret-here
    - old-secret-for-rotation  # Keep old secret temporarily
  cipher:
    - new-cipher-secret
    - old-cipher-secret

Monitoring and alerts

Security events to monitor

  • Failed login attempts
  • Account lockouts
  • Password reset requests
  • Session anomalies
  • Admin API access
  • Database connection failures

Logging

Enable comprehensive logging:
log:
  level: info
  format: json
  leak_sensitive_values: false  # Never enable in production

Log aggregation

Send logs to a centralized system:
  • ELK Stack (Elasticsearch, Logstash, Kibana)
  • Splunk
  • Datadog
  • CloudWatch Logs

Compliance

GDPR compliance

  • Implement data export (Admin API)
  • Support account deletion
  • Maintain audit logs
  • Encrypt data at rest
  • Use data processing agreements

Data retention

# Example: Automated cleanup of old sessions
cron:
  - schedule: "0 0 * * *"
    command: |
      DELETE FROM sessions 
      WHERE expires_at < NOW() - INTERVAL '90 days';

Security headers

Configure your reverse proxy with security headers:
add_header X-Frame-Options "DENY" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header Content-Security-Policy "default-src 'self'" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;

Security updates

1

Monitor releases

Watch the Kratos GitHub repository for security updates.
2

Subscribe to security advisories

3

Apply updates promptly

Test and deploy security patches quickly in production.

Next steps

CSRF protection

Learn about CSRF token handling

Rate limiting

Configure rate limits

Build docs developers (and LLMs) love