storage.go and a few optional extensions. A backend implements the ones it can, and New checks that every feature you enabled has the capability it needs. A missing one fails at startup with ErrStorageMissingCapability, not on the first request.
Three ways to supply storage
Config.Storagetakes the fulltheauth.Storage: users, sessions, magic links, passwords, OAuth accounts, WebAuthn, TOTP, organizations, SAML, SCIM, RBAC and audit.memory,postgresandmysqlsatisfy it.Config.CoreStoragetakestheauth.CoreStorage: users, sessions, magic links and passwords only. Anything else the adapter also implements is detected by type assertion. The rest are stubs that returnErrStorageMissingCapability.sqliteis used this way.- Optional extension interfaces are asserted against the storage you pass. If it implements one, the feature turns on. If not, the feature is off or degrades as noted below.
Storage and CoreStorage.
Capabilities and who implements them
Verified against the adapters in this repository. “Yes” means the adapter has the methods and, where the repo declares one, a compile-time assertion or a test for it.
Postgres and MySQL implement the token, device, session-management, TOTP replay, user-count and throttle capabilities, and the new
storagetest suites for them pass against live PostgreSQL 16 and MySQL 8. The older shared contract gate for those two adapters (THEAUTH_PG_CONTRACT, THEAUTH_MYSQL_CONTRACT) is still off in CI because some older subtests fail; see docs/ROADMAP.md. Treat Postgres and MySQL support for the newer features as newly added.
Notes:
- Without
JWTBearerStorage, JWT-bearer replay protection uses an in-process map and is lost on restart. WithoutCIBAStorage,/oauth/bc-authorizeis not mounted. - Without
TOTPReplayStorage, the last used TOTP step is tracked in process memory only. - Without
RecoveryCodeStorageorWebAuthnRenameStorage, the matching routes answer 501 and everything else works. - The login throttle store is a separate hook,
Config.LoginThrottle.Store. SQLite providesStore.ThrottleStore()so several processes on one database share counters. Others use the in-process default or a store you supply.
Which feature needs which capability
Agent tokens minted with
MintAgentToken are API tokens (kind=agent), so they need only APITokenStorage, not the OAuth server.
Choosing a backend
- memory: tests and demos. State is lost on restart.
- sqlite (
storage/sqlite, separate module, Go 1.26): single-binary and single-host apps, CLIs with a local server, edge boxes. Covers sign-in, passkeys, TOTP, sessions with step-up, API tokens, device login and audit. It has no organizations, SAML, SCIM, RBAC or OAuth authorization server. One process should own the file. - postgres: multi-instance production with the full enterprise and OAuth server surface, plus tokens, device login and session management. No durable JWT-bearer
jtireplay store. - mysql: same coverage as Postgres except CIBA.
storagetest suites (RunAPITokens, RunDeviceCodes, RunSessionManagement) against it.