dynamo

package
v0.5.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 21, 2026 License: Apache-2.0 Imports: 8 Imported by: 0

Documentation

Overview

Package dynamo stores single-use authentication ceremony state in DynamoDB.

It exists so a deployment with no relational database can run the passkey, OAuth, and OIDC ceremonies. Importing it registers the ceremony table; the client itself belongs to database/dynamo, which this package reads from the request context:

import _ "github.com/shibukawa/popcornweb/database/dynamo"
import _ "github.com/shibukawa/popcornweb/authstate/dynamo"

Nothing here sweeps expired records. Take decides expiry from the stored deadline, so correctness never waits for a deletion; removing the bytes is DynamoDB TTL on the expires_at attribute, which a deployment enables on the table it owns. The sqlite adapter publishes Prune because a bounded DELETE is cheap there. Here the equivalent is a Scan over every ceremony record ever written, which costs more than the records it would remove.

Index

Constants

View Source
const DeclaredTable = "popcornweb_authstate"

DeclaredTable is the name source uses. A deployment maps it onto its own through middleware.dynamo, like any other table.

Variables

This section is empty.

Functions

func NewStore

func NewStore[T any](codec authstate.Codec[T], options Options) (authstate.Store[T], error)

NewStore builds a typed store over NewRawStore, for a caller that owns a codec and wants the ordinary contract.

func Table

func Table(name string) dynamodb.TableDefinition

Table is the definition of the ceremony table. It is handwritten rather than generated: this package is the only reader and writer of the item, so the drift a generated codec closes cannot occur.

The partition key holds the namespace and the correlation key joined, rather than the namespace alone with the key as a sort key. Every ceremony of one protocol shares a namespace, so that shape would put a login spike on a single partition. What it gives up is a cheap namespace-scoped listing, which nothing needs once there is no prune.

Types

type Options

type Options struct {
	// Table is the declared table name. Empty means DeclaredTable.
	Table string
	// Namespace separates the ceremonies of one protocol from another's within
	// the one table. It is required.
	Namespace string
	// Now is injectable for tests.
	Now           func() time.Time
	MaxKeyBytes   int
	MaxValueBytes int
}

Options controls key isolation and resource bounds.

type Store

type Store struct {
	// contains filtered or unexported fields
}

Store persists expiring, single-use authentication state in DynamoDB.

It is a raw store: it works on already encoded payloads, so plugin/auth can open one for a ceremony type this package cannot name. NewStore puts the codec back on for a caller that has one.

func NewRawStore

func NewRawStore(options Options) (*Store, error)

NewRawStore builds the store. It opens nothing: the client comes from the request context, installed by the database/dynamo middleware. That is why it takes no client argument, unlike the sqlite adapter which takes a pool.

func (*Store) Put

func (s *Store) Put(ctx context.Context, key string, payload []byte, expiresAt time.Time) error

Put stores a value that has never been stored under this key, or whose previous record has already expired.

The condition carries the whole guarantee in one request: the item is absent, or its stored deadline has passed. That is the sqlite adapter's rule reached without a read followed by a conditional upsert.

func (*Store) Take

func (s *Store) Take(ctx context.Context, key string) ([]byte, error)

Take removes a value and returns it, atomically.

DeleteItem asking for the old item removes and returns in one request, so the single-use guarantee needs no read followed by a delete. This is the same shape as the sqlite adapter's DELETE RETURNING, and the reason both adapters can promise it.

Everything after the removal is validation of what came back. A malformed, expired, or undecodable record stays consumed: it was single-use, and handing it back would be worse than losing it.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL