Custom storage
Implement Authlier's behavioral storage contracts for another database.
Use a custom adapter when Authlier does not include your database. The adapter is application-side Go code that teaches Authlier how to persist every enabled capability; Authlier does not send records to a separate service.
Start with the root contract:
type Database interface {
Migrate(ctx context.Context) error
Stores() authlier.Stores
}Migrate prepares whatever schema, indexes, or other database structures the
adapter needs. Stores returns one implementation for each enabled Authlier
capability. The root authlier.New function selects those stores from the
adapter; normal application handlers do not call them.
For example, EmailPassword must implement user and password-credential
storage, Passkeys must implement the passkey store, and TOTP must implement
the TOTP store. Cookie mode requires Sessions. Bearer mode requires both
AccessSessions and RefreshTokens. A field may be nil only when the
corresponding feature is disabled.
Implement the behavior described by each package interface, not only matching method signatures. In particular, the adapter must preserve:
- unique users and provider identities;
- atomic creation and consumption of one-time tokens and protocol state;
- safe concurrent passkey counter updates;
- session rotation, expiry, and account-wide revocation;
- atomic creation and revocation of bearer access sessions and refresh tokens;
- refresh-token rotation and reuse detection.
Unit tests can check mapping and error behavior, but the adapter also needs integration tests against the real database. Only the real engine can prove its transaction, uniqueness, and concurrency behavior.
Read storage.go
for the aggregate contract, then follow the interfaces in the packages for the
features you enable. Pass the completed adapter to Config.Database in exactly
the same way as an official adapter.