Security by default
Security decisions are made at the framework level — not left as configuration exercises for the operator. Everything listed here ships in every Kotauth deployment with zero additional setup.
Cryptographic primitives
Industry-standard algorithms with no custom cryptography. Every secret follows the same principle: store the minimum necessary, in the strongest available form.
bcrypt (cost 12)
Password hashing — salted, time-resistant, brute-force infeasible
AES-256-GCM
Encryption at rest for RSA private keys, SMTP credentials, TOTP secrets, and social provider secrets
SHA-256
API key and token hashing — raw values never stored in the database
RS256 (RSA-SHA256)
Per-tenant JWT signing with auto-provisioned key pairs, encrypted at rest
HMAC-SHA256
Session cookie signing, webhook payload signing, OAuth state parameters
Protection layers
Multiple independent defenses — a failure in one layer doesn't compromise the system.
Account lockout
Configurable failed login threshold with automatic lockout duration. Locked users receive an email notification with a password reset link. Admins can manually unlock accounts.
Rate limiting
5 login attempts per minute, 5 MFA challenges per 5 minutes, 3 password resets per 5 minutes — all per IP per workspace. Tenant-scoped — one workspace's traffic never affects another.
Token rotation
Refresh tokens rotate on every use. Using an old refresh token immediately revokes the entire session chain — a stolen token has a single-use replay window at most.
Audit logging
30+ immutable event types recorded in the request path. No authentication flow succeeds without a corresponding audit record. Queryable via API and admin console.
OIDC end-session logout
RP-initiated logout with id_token_hint, server-side session revocation, cookie cleanup, and open redirect prevention on post_logout_redirect_uri.
Startup validation
Production mode refuses to start with HTTP base URLs, default secrets, or missing critical configuration. Unsafe defaults are rejected at boot, not discovered in production.
How secrets are stored
A database breach should reveal nothing usable. Every credential type has its own storage strategy.
| Secret | Storage method |
|---|---|
| User passwords | bcrypt hash (cost 12). Raw password discarded after verification. |
| Client secrets | bcrypt hash. Raw value shown once at generation, never retrievable. |
| API keys | SHA-256 hash. Format: kauth_{slug}_{random}. Prefix stored for display. |
| Refresh tokens | SHA-256 hash. Rotate on every use. Old token revokes session. |
| RSA private keys | AES-256-GCM encrypted at rest. Plaintext keys auto-migrated on first startup. |
| SMTP credentials | AES-256-GCM encrypted at rest. Key derived from KAUTH_SECRET_KEY. |
| Social provider secrets | AES-256-GCM encrypted at rest. Same key derivation. |
| MFA TOTP secrets | AES-256-GCM encrypted at rest. Base32-encoded for QR URI. |
| Recovery codes | bcrypt hash. One-time use. 8 codes generated per MFA enrollment. |
Transport & request hardening
Configurable per workspace
Every workspace defines its own password policy. All settings configurable from the admin console.
Report a vulnerability
If you discover a security vulnerability, please report it privately via GitHub Security Advisories. Do not open a public issue. We take all reports seriously and will respond promptly.