Skip to main content
Ory Kratos uses multiple layers of encryption and hashing to protect sensitive user data.

Password hashing

Kratos supports two password hashing algorithms: Argon2id is the recommended hashing algorithm for new deployments:
hashers:
  algorithm: argon2
  argon2:
    memory: 131072      # 128 MB
    iterations: 3       # Time cost
    parallelism: 4      # CPU threads
    salt_length: 16     # Salt bytes
    key_length: 32      # Output hash length
memory
number
Memory cost in KB. Higher values increase security but require more RAM.Recommended: 128 MB (131072 KB) or higher
iterations
number
Time cost (number of iterations). Higher values increase computation time.Recommended: 3-4 iterations
parallelism
number
Degree of parallelism (number of threads). Should match available CPU cores.Recommended: 4 threads
salt_length
number
Length of the random salt in bytes.Recommended: 16 bytes
key_length
number
Length of the resulting hash in bytes.Recommended: 32 bytes

Bcrypt (legacy)

Bcrypt is supported for backward compatibility:
hashers:
  algorithm: bcrypt
  bcrypt:
    cost: 12  # Work factor (2^12 iterations)
cost
number
Bcrypt work factor. Each increment doubles the computation time.Recommended: 12 or higher (minimum: 10)
Argon2id is more resistant to GPU and ASIC attacks than bcrypt. Use Argon2id for new deployments.

Password hashing comparison

AlgorithmSecurityPerformanceResistance to
Argon2idExcellentGoodGPU, ASIC, side-channel attacks
BcryptGoodModerateGeneral attacks

Credential encryption

Kratos encrypts sensitive credential data at rest using AES-256-GCM:

OIDC provider tokens

OAuth tokens from OIDC providers are encrypted:
// From identity/credentials_oidc.go
type CredentialsOIDC struct {
	Providers []ProviderCredentials `json:"providers"`
}

type ProviderCredentials struct {
	Provider              string `json:"provider"`
	Subject               string `json:"subject"`
	InitialIDToken        string `json:"initial_id_token"`        // Encrypted
	InitialAccessToken    string `json:"initial_access_token"`    // Encrypted
	InitialRefreshToken   string `json:"initial_refresh_token"`   // Encrypted
}

WebAuthn credentials

WebAuthn authenticator data is encrypted:
// From identity/credentials_webauthn.go
type CredentialsWebAuthn struct {
	Credentials []CredentialWebAuthn `json:"credentials"`
}

type CredentialWebAuthn struct {
	ID              []byte `json:"id"`
	PublicKey       []byte `json:"public_key"`       // Encrypted
	AttestationType string `json:"attestation_type"`
	Authenticator   webauthn.Authenticator `json:"authenticator"` // Encrypted
}

Cipher secrets

Configure encryption secrets in your configuration:
secrets:
  cipher:
    - your-32-character-secret-key-here
    - old-key-for-rotation-support
Cipher secrets must be exactly 32 characters (256 bits) for AES-256 encryption.

Generate secure cipher secrets

openssl rand -base64 32

Secret rotation

Kratos supports secret rotation for both cipher and cookie secrets:
secrets:
  cipher:
    - new-secret-active-key
    - old-secret-for-decryption-only
    - older-secret-for-legacy-data
  cookie:
    - new-cookie-secret
    - old-cookie-secret

Rotation process

1

Add new secret

Add the new secret at the beginning of the array:
secrets:
  cipher:
    - new-secret-key  # Used for new encryptions
    - old-secret-key  # Still valid for decryption
2

Deploy configuration

Deploy Kratos with the updated configuration. Both keys are now valid.
3

Wait for transition period

Wait for all encrypted data to be re-encrypted with the new key. This happens gradually as data is accessed and updated.
4

Remove old secret

After sufficient time (e.g., 30-90 days), remove the old secret:
secrets:
  cipher:
    - new-secret-key  # Only key

Database encryption

Encryption at rest

Enable database-level encryption:
Use Transparent Data Encryption (TDE) or encrypted storage:
-- Enable pgcrypto extension
CREATE EXTENSION IF NOT EXISTS pgcrypto;

-- Use encrypted tablespaces (requires OS-level encryption)
CREATE TABLESPACE encrypted LOCATION '/encrypted/data';
ALTER DATABASE kratos SET TABLESPACE encrypted;
Or use storage-level encryption (e.g., LUKS, AWS EBS encryption).

Encrypted connections

Always use SSL/TLS for database connections:
dsn: postgres://user:pass@host/db?sslmode=require
sslmode
string
SSL mode for PostgreSQL:
  • require: Require SSL (recommended minimum)
  • verify-ca: Require SSL and verify CA certificate
  • verify-full: Require SSL and verify hostname (most secure)
  • disable: No SSL (never use in production)

Session tokens

Session tokens are cryptographically secure random strings:
// From session/tokenizer.go
const (
	TokenLength = 32  // 256-bit token
)

func NewToken() string {
	b := make([]byte, TokenLength)
	if _, err := rand.Read(b); err != nil {
		panic(err)
	}
	return base64.RawURLEncoding.EncodeToString(b)
}
Tokens are:
  • 256 bits of entropy
  • Base64 URL-safe encoded
  • Cryptographically random
  • Stored as opaque values
Session cookies are encrypted and signed:
secrets:
  cookie:
    - your-32-character-cookie-secret
Cookie secrets are used for:
  • Encrypting session data in cookies
  • Signing cookies to prevent tampering
  • CSRF token generation
Kratos uses gorilla/securecookie for cookie encryption with AES-256-GCM and HMAC-SHA256.

HTTPS/TLS

Always use HTTPS in production:
serve:
  public:
    base_url: https://auth.example.com/
  admin:
    base_url: https://admin.example.com/

cookies:
  secure: true  # Only send cookies over HTTPS

TLS configuration

Terminate TLS at a reverse proxy (recommended):
server {
    listen 443 ssl http2;
    server_name auth.example.com;
    
    ssl_certificate /etc/ssl/certs/auth.example.com.crt;
    ssl_certificate_key /etc/ssl/private/auth.example.com.key;
    
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;
    
    location / {
        proxy_pass http://kratos:4433;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Encryption key management

Best practices

1

Use a key management service

Store encryption keys in a secure key management service:
  • AWS KMS
  • Google Cloud KMS
  • Azure Key Vault
  • HashiCorp Vault
2

Rotate keys regularly

Implement a key rotation schedule (e.g., every 90 days).
3

Never commit keys to version control

Use environment variables or secret management tools.
4

Audit key usage

Enable logging and monitoring for key access.

Example: AWS KMS integration

#!/bin/bash
# Retrieve cipher secret from AWS KMS
CIPHER_SECRET=$(aws kms decrypt \
  --ciphertext-blob fileb://encrypted-secret.bin \
  --query Plaintext \
  --output text | base64 --decode)

export SECRETS_CIPHER="$CIPHER_SECRET"
kratos serve -c config.yml

Compliance

GDPR

Encryption supports GDPR compliance:
  • Data protection by design
  • Pseudonymization of personal data
  • Security of processing (Article 32)

PCI DSS

For payment card data:
  • Use strong cryptography (AES-256)
  • Protect encryption keys
  • Regularly rotate keys
  • Encrypt data in transit and at rest

Monitoring

Monitor encryption-related events:
log:
  level: info
  format: json
Key events to track:
  • Decryption failures (may indicate key rotation issues)
  • Hashing failures
  • TLS handshake errors
  • Key rotation events

Next steps

Best practices

Complete security hardening guide

CSRF protection

Learn about CSRF tokens

Build docs developers (and LLMs) love