Skip to main content
theauth-go does not require one monolithic storage interface. Persistence is split into small capability interfaces in 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.Storage takes the full theauth.Storage: users, sessions, magic links, passwords, OAuth accounts, WebAuthn, TOTP, organizations, SAML, SCIM, RBAC and audit. memory, postgres and mysql satisfy it.
  • Config.CoreStorage takes theauth.CoreStorage: users, sessions, magic links and passwords only. Anything else the adapter also implements is detected by type assertion. The rest are stubs that return ErrStorageMissingCapability. sqlite is 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.
Set exactly one of 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. Without CIBAStorage, /oauth/bc-authorize is not mounted.
  • Without TOTPReplayStorage, the last used TOTP step is tracked in process memory only.
  • Without RecoveryCodeStorage or WebAuthnRenameStorage, the matching routes answer 501 and everything else works.
  • The login throttle store is a separate hook, Config.LoginThrottle.Store. SQLite provides Store.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 jti replay store.
  • mysql: same coverage as Postgres except CIBA.
Pick by the features you need first, host topology second. SQLite is the fit for a single-binary app without organizations, SAML, SCIM or the authorization server. If you need those, use Postgres or MySQL. You can also implement a capability on your own adapter; see Write a Custom Storage Backend and run the storagetest suites (RunAPITokens, RunDeviceCodes, RunSessionManagement) against it.
Last modified on October 7, 2026