Documentation
¶
Overview ¶
Package authstate provides expiring, single-use state storage for browser authentication flows.
Index ¶
- Constants
- Variables
- func Dialects() []string
- func Register(dialect Dialect)
- func ScanColumns(rows *sql.Rows) ([]string, error)
- func SchemaSQL(dialect string) (string, error)
- type Codec
- type Dialect
- type RawCodec
- type RawStore
- type SQLOptions
- type SQLRecord
- type SQLStore
- func (s *SQLStore[T]) EnsureSchema(ctx context.Context) error
- func (s *SQLStore[T]) Prune(ctx context.Context, before time.Time, limit int) (int64, error)
- func (s *SQLStore[T]) Put(ctx context.Context, key string, value T, expiresAt time.Time) error
- func (s *SQLStore[T]) Take(ctx context.Context, key string) (T, error)
- type Store
Constants ¶
const TableName = "popcornweb_authstate"
TableName is the table the SQL stores own.
Variables ¶
var ( ErrNotFound = errors.New("authstate: state not found") ErrExpired = errors.New("authstate: state expired") ErrAlreadyExists = errors.New("authstate: state already exists") ErrLimitExceeded = errors.New("authstate: store limit exceeded") ErrInvalidKey = errors.New("authstate: invalid key") ErrInvalidExpiry = errors.New("authstate: invalid expiry") ErrInvalidOptions = errors.New("authstate: invalid options") ErrCodec = errors.New("authstate: codec failure") )
var Columns = []string{"namespace", "key", "expires_at_ms", "payload"}
Columns are the columns of that table, in the order every dialect declares them.
Functions ¶
func Register ¶
func Register(dialect Dialect)
Register adds an engine's dialect. An engine package calls it from init, so a blank import is what makes the SQL store work against that engine:
import _ "github.com/shibukawa/popcornweb/authstate/postgres"
A duplicate or incomplete dialect panics: two descriptions of one engine is a build mistake, not a runtime condition.
func ScanColumns ¶
ScanColumns reads one column name per row, which is the shape every engine's catalog query is written to return.
Types ¶
type Codec ¶
Codec explicitly serializes values stored by durable Store implementations. Implementations must use a versioned, bounded format and must not include value contents in returned errors.
type Dialect ¶
type Dialect struct {
// Name is the dialect identifier rule:rdb-dsn-resolution resolves a DSN
// scheme to.
Name string
// CreateTable is the deterministic DDL of the owned table.
CreateTable func() string
// Insert stores one record unless a live one already holds the key, and
// reports whether it stored.
Insert func(ctx context.Context, db *sql.DB, record SQLRecord) (bool, error)
// Take removes one record and returns what it held. A missing record is
// sql.ErrNoRows, which the store reports as ErrNotFound.
Take func(ctx context.Context, db *sql.DB, namespace, key string) (expiresAtMS int64, payload []byte, err error)
// Prune removes at most limit records of one namespace that expired
// before the given instant.
Prune func(ctx context.Context, db *sql.DB, namespace string, beforeMS int64, limit int) (int64, error)
// Columns lists the columns of the owned table in declaration order, or
// none at all when the table does not exist.
Columns func(ctx context.Context, db *sql.DB) ([]string, error)
}
Dialect is one engine's implementation of the four operations a SQL-backed store performs. These are whole operations rather than statement fragments because the engines differ in more than syntax: MySQL has no RETURNING, so its single-use read is a transaction where the others are one statement.
func DialectFor ¶
DialectFor resolves one engine, explaining the missing import rather than the missing map entry.
type RawCodec ¶
type RawCodec struct{}
RawCodec passes payloads through unchanged, so a typed store can serve as a RawStore for a caller that owns the encoding itself.
type RawStore ¶
type RawStore interface {
Put(ctx context.Context, key string, payload []byte, expiresAt time.Time) error
Take(ctx context.Context, key string) ([]byte, error)
}
RawStore is Store over already encoded payloads.
It exists so a storage backend can open a ceremony store for a value type it cannot name. plugin/auth keeps three kinds of ceremony record, two of whose types are unexported, so a backend package could never construct a Store[T] for them; it supplies this instead and the host adds the codec back with Typed.
The guarantees are the ones Store states: Take removes a value before returning it, an expired value is removed and never returned, and a stable error reveals nothing about what was stored.
type SQLOptions ¶
type SQLOptions struct {
// Dialect is the registered engine name, which is the dialect the DSN
// scheme already resolved to.
Dialect string
Namespace string
Now func() time.Time
MaxKeyBytes int
MaxValueBytes int
MaxPruneBatch int
}
SQLOptions controls record isolation, resource bounds, and expiry behavior, and names the engine the statements run against.
type SQLRecord ¶
SQLRecord is one row an Insert writes. NowMS decides whether an existing row is stale enough to replace: a live record is never overwritten, which is what makes a ceremony key single use.
type SQLStore ¶
type SQLStore[T any] struct { // contains filtered or unexported fields }
SQLStore persists expiring, single-use authentication state in a database/sql database. The engine is supplied by a registered Dialect, so this type carries no SQL of its own beyond what every engine shares.
func NewSQLRawStore ¶
NewSQLRawStore constructs a SQL store over already encoded payloads, which is the form a storage backend supplies for a value type it cannot name.
func NewSQLStore ¶
NewSQLStore constructs a store over db under the named engine. The caller retains ownership of db and must carry the migration, or call EnsureSchema, before serving requests.
func (*SQLStore[T]) EnsureSchema ¶
EnsureSchema creates the owned table when it is missing and verifies its column layout, which is what a project carrying the migration relies on at startup.
func (*SQLStore[T]) Prune ¶
Prune removes at most limit expired records from this Store's namespace.
type Store ¶
type Store[T any] interface { Put(ctx context.Context, key string, value T, expiresAt time.Time) error Take(ctx context.Context, key string) (T, error) }
Store atomically persists and consumes expiring authentication state. Implementations must remove a value before a successful Take returns.
Directories
¶
| Path | Synopsis |
|---|---|
|
Package dynamo stores single-use authentication ceremony state in DynamoDB.
|
Package dynamo stores single-use authentication ceremony state in DynamoDB. |
|
Package firestore stores single-use authentication ceremony state in Firestore in Datastore mode.
|
Package firestore stores single-use authentication ceremony state in Firestore in Datastore mode. |
|
Package memory provides process-local authentication state storage.
|
Package memory provides process-local authentication state storage. |
|
Package mysql registers the MySQL dialect of the authentication state store.
|
Package mysql registers the MySQL dialect of the authentication state store. |
|
Package postgres registers the PostgreSQL dialect of the authentication state store.
|
Package postgres registers the PostgreSQL dialect of the authentication state store. |
|
Package redis provides a Redis and Valkey backed authstate.Store.
|
Package redis provides a Redis and Valkey backed authstate.Store. |
|
Package sqlite registers the SQLite dialect of the authentication state store.
|
Package sqlite registers the SQLite dialect of the authentication state store. |