Release history
Every release, with what changed and why. Kotauth follows semantic versioning.
Two root compose files (docker-compose.yml + docker-compose.prod.yml) replace six that lived under docker/
External-DB overlay replaced by DB_URL in .env; demo overlay replaced by KAUTH_DEMO_MODE=true in .env
All deployment guidance moved to docs; comments stripped from Dockerfile, Caddyfile, and compose files
File-based secret injection (*_FILE convention) for KAUTH_SECRET_KEY, DB_PASSWORD, KAUTH_REDIS_PASSWORD, KAUTH_BOOTSTRAP_ADMIN_PASSWORD, and KAUTH_BOOTSTRAP_API_KEYS
Gradle dependency locking: gradle.lockfile pins the resolved dependency graph, CI verifies on every PR
Dependabot enabled for weekly alerts on Gradle deps, GitHub Actions, and Docker base images
HMAC chain over audit log: each row carries prev_hash and row_hash via HMAC-SHA256 keyed by KAUTH_SECRET_KEY; tampering or reordering breaks the chain
New verify-audit-chain CLI command detects tampered or reordered audit rows
Audit log details now use kotlinx.serialization, fixing silent JSON corruption from hand-concatenated strings
Multi-audience token introspection: AccessTokenClaims.aud widened to support array format
RFC 8707 Resource Indicators for client_credentials grant: audience-targeted M2M tokens with aud bound to the requested resource
APIs registry (admin: /settings/apis): workspace-scoped CRUD for audience identifiers
Per-client "Authorized APIs" screen with checkbox authorization and Discovery metadata advertising resource_indicators_supported: true
Unknown or unauthorized resources return RFC 8707 invalid_target 400 instead of a silently-broad token
All 8 transactional email types localized: verification, magic link, password reset, account locked, invite, password changed, SMTP test, and OTP
Email templates render in the workspace defaultLocale with per-key English fallback
Trusted proxy opt-in (KAUTH_TRUSTED_PROXY): prevents rate-limit bypass via header spoofing
JWT issuer enforcement: tokens issued by one tenant are rejected by another
Open redirect prevention: post-login redirect_uri validated against registered values
PKCE S256 code verifier comparison uses constant-time equality
Server response header suppressed from HTTP responses
Login error normalization with timing equalization prevents user enumeration
Container ships non-root (UID 10001) with no-new-privileges, cap_drop: ALL, and read-only filesystem
TOTP replay protection: each code is single-use per enrollment; lockout after configurable failed attempts
Theme CSS variable validation prevents injection of arbitrary values via workspace settings
Login error timing equalized across password and TOTP verification paths
AdminService split into AuthManagementService, UserAdminService, and WorkspaceAdminService
UserSelfServiceService split into UserProfileService and UserSecurityService
Detekt ratchet tightened: complexity and coupling rules enforced in CI
BREAKING: Default admin credential removed. A random password is generated on first boot and logged once to stdout.
BREAKING: Refresh token endpoint now requires client authentication (client_id + client_secret for confidential clients)
BREAKING: Introspection and revocation endpoints require client authentication per RFC 7662 / RFC 7009
Refresh-token replay detection with full session-family revocation on reuse
Account lockout with configurable threshold and admin unlock UI
Hosted Email OTP login: browser-driven two-step passwordless authentication (enter email, receive 6-digit code, sign in)
Per-tenant toggle for Email OTP via workspace settings
send-otp / verify-otp admin API primitives for programmatic passwordless onboarding
Cross-challenge lockout defense: per-tenant OTP attempt threshold with constant-time response posture
Bootstrap API key prefix mismatch: kauth_{slug}_ now consistently applied at generation and validation
Redirect-URI validation tightened: exact match required, trailing-slash variants rejected
OpenAPI spec updated with OTP send/verify endpoints and audit log filter documentation
Audit log filter groups surfaced in admin UI for cleaner event category browsing
Client default roles: per-application roles automatically assigned to users who self-register through an OAuth application
Registration Defaults card in admin console with dropdown and role management table
Cross-client privilege-escalation guard: roles from other applications cannot be assigned as defaults
Transactional email branding: per-tenant brand name, color, logo URL, support email, and from display name
All 8 transactional email templates inherit workspace branding automatically
Branding editor card in workspace settings with live preview
Admin impersonation: act as any user without knowing their password, with RFC 8693 act claim in the session token
Dual-session model: admin session stays active underneath the impersonated session
Cascade revocation: revoking the admin session also terminates the impersonated session
AI-native MCP server (@kotauth/mcp): 33 tools across 8 domains exposed via Model Context Protocol
Scope-based access control on every MCP tool: API key grants only the permissions you choose
One-command connect: npx @kotauth/mcp