Documentation
¶
Overview ¶
Package store defines the storage boundary of Auth-All. The application owns the database. An adapter implements these capability-oriented interfaces.
Index ¶
Constants ¶
This section is empty.
Variables ¶
var ( // ErrNotFound reports that the requested row does not exist. ErrNotFound = errors.New("authall/store: not found") // ErrConflict reports that a uniqueness constraint rejected the write. ErrConflict = errors.New("authall/store: conflict") )
Sentinel storage errors.
Functions ¶
This section is empty.
Types ¶
type Account ¶
type Account struct {
ID string
UserID string
Provider string
ProviderAccountID string
CreatedAt time.Time
UpdatedAt time.Time
}
Account is one external provider identity owned by a user.
type AccountStore ¶
type AccountStore interface {
// Create inserts an account. It returns ErrConflict when the provider
// identity is already linked to a user.
Create(ctx context.Context, a *Account) error
GetByProviderAccount(ctx context.Context, provider, providerAccountID string) (*Account, error)
ListByUser(ctx context.Context, userID string) ([]Account, error)
// Delete removes one link. It returns ErrNotFound when no link exists.
Delete(ctx context.Context, userID, provider string) error
}
AccountStore holds external provider identities.
type Credential ¶
type Credential struct {
UserID string
PasswordHash string
CreatedAt time.Time
UpdatedAt time.Time
}
Credential is the password credential of one user.
type Migrator ¶
type Migrator interface {
// Dialect reports the SQL flavor of the adapter.
Dialect() schema.Dialect
// Plan returns the statements that are not applied yet.
Plan(ctx context.Context, s *schema.Schema) ([]schema.Statement, error)
// Apply runs the pending statements and records them.
Apply(ctx context.Context, s *schema.Schema) ([]schema.Statement, error)
// Check returns an actionable error when the database schema is missing or
// outdated.
Check(ctx context.Context, s *schema.Schema) error
}
Migrator applies the effective schema. It never runs automatically.
type OAuthState ¶
type OAuthState struct {
ID string
StateHash string
Provider string
Verifier string
Nonce string
RedirectTo string
LinkUserID *string
CreatedAt time.Time
ExpiresAt time.Time
ConsumedAt *time.Time
}
OAuthState is one pending OAuth authorization request.
type OAuthStateStore ¶
type OAuthStateStore interface {
Create(ctx context.Context, s *OAuthState) error
// Consume atomically marks one unconsumed and unexpired state as consumed
// and returns it.
Consume(ctx context.Context, stateHash string, now time.Time) (*OAuthState, error)
DeleteExpired(ctx context.Context, before time.Time) (int, error)
}
OAuthStateStore holds pending OAuth authorization requests.
type RecoveryCodeStore ¶ added in v0.2.0
type RecoveryCodeStore interface {
// ReplaceAll removes every code of the user and writes the supplied
// hashes. It runs in one transaction, so a failure never leaves the user
// with no codes.
ReplaceAll(ctx context.Context, userID string, hashes []string) error
// Consume removes one code of one user and reports whether a row matched.
//
// The match and the removal are one atomic operation. Two concurrent calls
// that carry the same code must produce at most one true, because a
// recovery code carries a complete sign-in.
//
// An unknown code reports false and no error.
Consume(ctx context.Context, userID, codeHash string) (bool, error)
// CountByUser returns the number of unused codes of one user.
CountByUser(ctx context.Context, userID string) (int, error)
// DeleteByUser removes every code of one user and returns the count.
DeleteByUser(ctx context.Context, userID string) (int, error)
}
RecoveryCodeStore holds the recovery codes of the second factor.
A recovery code is a first factor and a second factor at once, so the store keeps only the SHA-256 hash. A recovery code carries about 49 bits from a random source, so it needs no slow password hash.
type Session ¶
type Session struct {
ID string
UserID string
TokenHash string
CreatedAt time.Time
ExpiresAt time.Time
LastSeenAt time.Time
}
Session is one database-backed opaque session. TokenHash never holds a plaintext token.
type SessionStore ¶
type SessionStore interface {
Create(ctx context.Context, s *Session) error
GetByTokenHash(ctx context.Context, tokenHash string) (*Session, error)
// ListByUser returns every session of one user, and the newest comes
// first. It returns an empty result for a user without a session.
ListByUser(ctx context.Context, userID string) ([]Session, error)
// Touch updates last_seen_at. It returns ErrNotFound when the session no
// longer exists, so a revoked session cannot be resurrected.
Touch(ctx context.Context, id string, at time.Time) error
Delete(ctx context.Context, id string) error
DeleteByUser(ctx context.Context, userID string) (int, error)
DeleteExpired(ctx context.Context, before time.Time) (int, error)
}
SessionStore holds database-backed sessions.
type Store ¶
type Store interface {
Users() UserStore
Accounts() AccountStore
Sessions() SessionStore
Tokens() TokenStore
OAuthStates() OAuthStateStore
TOTP() TOTPStore
RecoveryCodes() RecoveryCodeStore
// Transaction runs fn inside one database transaction. The Store passed to
// fn performs every operation inside that transaction.
Transaction(ctx context.Context, fn func(Store) error) error
// Migrator returns the schema migrator of the adapter.
Migrator() Migrator
// Close releases adapter resources. It does not close a database handle
// owned by the application.
Close() error
}
Store is the storage boundary of Auth-All.
type TOTP ¶ added in v0.2.0
type TOTP struct {
UserID string
Secret string
// ConfirmedAt is nil until the user proves one code. An unconfirmed
// enrolment never authenticates a sign-in.
ConfirmedAt *time.Time
// LastStep is the last accepted time step. The sign-in gate refuses a step
// that is not greater than this value, which stops a replay of one code
// inside its own window.
LastStep int64
CreatedAt time.Time
UpdatedAt time.Time
}
TOTP is the time-based one-time password enrolment of one user.
Secret holds the base32 shared secret. Auth-All does not encrypt it, because Auth-All holds no application key, and a key that the library invents lives in the same database as the secret. An application that needs encryption at rest applies it at the column or at the volume.
type TOTPStore ¶ added in v0.2.0
type TOTPStore interface {
// Get returns the enrolment of one user. It returns ErrNotFound when the
// user holds no secret.
Get(ctx context.Context, userID string) (*TOTP, error)
// Upsert writes the enrolment of one user and replaces any existing row.
// A replacement clears the confirmation and the last step, because a new
// secret starts a new enrolment.
Upsert(ctx context.Context, t *TOTP) error
// Confirm marks the enrolment of one user as proven. It returns
// ErrNotFound when the user holds no secret.
Confirm(ctx context.Context, userID string, at time.Time) error
// AdvanceStep records step when it is greater than the stored step, and
// reports whether the write happened.
//
// The comparison and the write are one atomic operation. Two concurrent
// calls that carry the same step must produce at most one true, because a
// read followed by a later write would let an attacker replay one stolen
// code across parallel requests.
//
// It returns ErrNotFound when the user holds no secret.
AdvanceStep(ctx context.Context, userID string, step int64) (bool, error)
// Delete removes the enrolment of one user. It returns ErrNotFound when
// the user holds no secret.
Delete(ctx context.Context, userID string) error
}
TOTPStore holds the TOTP enrolment of each user.
type Token ¶
type Token struct {
ID string
UserID *string
Kind string
Identifier string
TokenHash string
CreatedAt time.Time
ExpiresAt time.Time
ConsumedAt *time.Time
}
Token is one one-time token. TokenHash never holds a plaintext token.
type TokenStore ¶
type TokenStore interface {
Create(ctx context.Context, t *Token) error
// Consume atomically marks one unconsumed and unexpired token as consumed
// and returns it. Two concurrent calls for the same token must produce at
// most one success. It returns ErrNotFound otherwise.
Consume(ctx context.Context, kind, tokenHash string, now time.Time) (*Token, error)
// Get returns a token without consuming it.
Get(ctx context.Context, kind, tokenHash string) (*Token, error)
// DeleteByIdentifier removes every outstanding token of one kind for one
// identifier.
DeleteByIdentifier(ctx context.Context, kind, identifier string) error
DeleteExpired(ctx context.Context, before time.Time) (int, error)
}
TokenStore holds one-time tokens.
type User ¶
type User struct {
ID string
Email string
EmailNormalized string
EmailVerifiedAt *time.Time
DisplayName string
ImageURL string
CreatedAt time.Time
UpdatedAt time.Time
}
User is one Auth-All user.
type UserStore ¶
type UserStore interface {
// Create inserts a user. It returns ErrConflict when the normalized email
// is already taken.
Create(ctx context.Context, u *User) error
GetByID(ctx context.Context, id string) (*User, error)
GetByNormalizedEmail(ctx context.Context, normalized string) (*User, error)
// Update writes the mutable user fields.
Update(ctx context.Context, u *User) error
// Delete removes a user and every owned row.
Delete(ctx context.Context, id string) error
GetCredential(ctx context.Context, userID string) (*Credential, error)
// SetCredential inserts or replaces the password credential of a user.
SetCredential(ctx context.Context, c *Credential) error
DeleteCredential(ctx context.Context, userID string) error
}
UserStore holds users and password credentials.
Directories
¶
| Path | Synopsis |
|---|---|
|
Package postgres provides the PostgreSQL storage adapter for Auth-All.
|
Package postgres provides the PostgreSQL storage adapter for Auth-All. |
|
Package sqlite provides the SQLite storage adapter for Auth-All.
|
Package sqlite provides the SQLite storage adapter for Auth-All. |
|
Package storetest holds the behavioral contract suite that every Auth-All storage adapter must pass.
|
Package storetest holds the behavioral contract suite that every Auth-All storage adapter must pass. |