Back to home Security

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.

Cryptography

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

Defense in depth

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.

Data protection

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

Transport & request hardening

Content-Security-Policy with strict script-src 'self' (zero inline JavaScript) — style-src permits 'unsafe-inline' for server-injected theme tokens; all other directives locked to 'self'
SRI integrity hashes on all bundled JavaScript — prevents tampering with static assets
SameSite=Lax on all session cookies (admin and portal)
Secure cookie flag derived from KAUTH_BASE_URL scheme at startup
CSRF protection via OAuth state parameter + PKCE cookie signatures
HTTPS enforcement in production mode — HTTP refused at startup
Open redirect prevention on OIDC end-session endpoint
PKCE required for all public OAuth clients (S256 only)
Password policy

Configurable per workspace

Every workspace defines its own password policy. All settings configurable from the admin console.

Configurable minimum length (4–128 characters)
Require uppercase, lowercase, numbers, and/or special characters
Password history — prevent reuse of last N passwords (0–24)
Password max age — force expiry after N days (0–365)
Password blacklist — reject known-compromised passwords
bcrypt cost factor 12 — raw passwords never stored or logged
Reporting

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.