sessionstate

package
v4.0.2 Latest Latest
Warning

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

Go to latest
Published: Oct 26, 2026 License: GPL-3.0 Imports: 16 Imported by: 0

Documentation

Overview

Package sessionstate defines the durable browser-session ownership and persistence contracts.

Index

Constants

View Source
const EncodedHandleLength = 43

EncodedHandleLength is the unpadded base64url length of a 256-bit handle.

View Source
const LegacyCookieKeyCount = 84

LegacyCookieKeyCount is the audited number of legacy primary-cookie fields.

Variables

View Source
var (
	ErrNotFound         = errors.New("session record not found")
	ErrRevisionConflict = errors.New("session record revision conflict")
	ErrParentMissing    = errors.New("session record parent missing")
	ErrBindingMismatch  = errors.New("session record binding mismatch")
	ErrExpired          = errors.New("session record expired")
	ErrRevoked          = errors.New("session record revoked")
	ErrInvalidTTL       = errors.New("session record invalid TTL")
	ErrActiveFlowLimit  = errors.New("session active flow limit reached")
)

Store errors are stable fail-closed classifications for callers and tests.

Functions

func NormalizeConsentScopes

func NormalizeConsentScopes(scopes []string) ([]string, error)

NormalizeConsentScopes returns one deterministic bounded scope set for persistence.

func RedisClusterHashTag

func RedisClusterHashTag(key string) string

RedisClusterHashTag returns the explicit cluster hash tag from a derived key.

Types

type AssuranceSummary

type AssuranceSummary struct {
	Level     int
	Method    string
	Scope     string
	ProvenAt  time.Time
	ExpiresAt time.Time
}

AssuranceSummary is the stable, non-secret MFA assurance shared by protocol flows.

type BackendAffinitySummary

type BackendAffinitySummary struct {
	Type        string
	Name        string
	Protocol    string
	Authority   string
	OpaqueToken string
}

BackendAffinitySummary binds follow-up operations to an authority backend without browser exposure.

type CeremonyRecord

type CeremonyRecord struct {
	Record
	Session           Handle
	Flow              Handle
	IdentityReference string
	Protocol          string
	Kind              string
	Attempt           uint64
	Payload           json.RawMessage
	ConsumedAt        time.Time
}

CeremonyRecord owns one short-lived single-use WebAuthn operation.

type Clock

type Clock interface {
	Now() time.Time
}

Clock owns wall-clock access for expiry and freshness decisions.

type CommitRequest

type CommitRequest[T any] struct {
	Reference        Reference
	ExpectedRevision Revision
	Value            T
	TTL              time.Duration
}

CommitRequest describes one typed revision-checked write without prescribing a Redis encoding.

type ConsentGrant

type ConsentGrant struct {
	Record
	IdentityReference string
	ClientID          string
	Scopes            []string
	GrantedAt         time.Time
	GrantExpiresAt    time.Time
}

ConsentGrant is one longer-lived OIDC consent bound to a stable identity and client.

func (ConsentGrant) Covers

func (g ConsentGrant) Covers(requested []string, now time.Time) bool

Covers reports whether a live grant contains every requested normalized scope.

type Contract

type Contract struct {
	Invariant    Invariant
	RuntimeOwner string
	TestOwner    string
}

Contract maps an invariant to the future runtime and test owners.

func ContractFor

func ContractFor(invariant Invariant) (Contract, bool)

ContractFor returns the executable ownership mapping for one invariant.

type DeleteRequest

type DeleteRequest struct {
	Reference        Reference
	ExpectedRevision Revision
}

DeleteRequest describes one revision-checked cleanup operation.

type EnrollmentRecord

type EnrollmentRecord struct {
	Record
	Session           Handle
	Flow              Handle
	AccountReference  string
	IdentityReference string
	RequiredMethods   []string
	CompletedMethods  []string
	CurrentStep       string
	Continuation      string
	Completed         bool
	// SelfService binds an optional enrollment to the authenticated session instead of a protocol flow.
	SelfService bool
}

EnrollmentRecord owns one required-factor enrollment state machine.

type Event

type Event struct {
	Kind  EventKind
	Owner Owner
}

Event is a bounded telemetry event and intentionally carries no raw identifiers.

type EventKind

type EventKind string

EventKind is a bounded identifier-free session telemetry classification.

const (
	EventLoadFailure     EventKind = "load_failure"
	EventCommitFailure   EventKind = "commit_failure"
	EventCleanupFailure  EventKind = "cleanup_failure"
	EventFormatRejection EventKind = "format_rejection"
	EventSafeRestart     EventKind = "safe_restart"
)

Event kinds are the complete bounded telemetry outcome vocabulary.

type Handle

type Handle string

Handle is an opaque, non-semantic reference to one server-side record.

func ParseHandle

func ParseHandle(value string) (Handle, error)

ParseHandle validates and returns one canonical 256-bit opaque handle.

type HandleGenerator

type HandleGenerator interface {
	NewHandle() (Handle, error)
}

HandleGenerator creates cryptographically random opaque references.

type IdentitySummary

type IdentitySummary struct {
	Account     string
	Subject     string
	DisplayName string
	Protocol    string
}

IdentitySummary is the bounded, non-secret authenticated identity projection used by browser flows.

type Invariant

type Invariant string

Invariant names one architecture property that must remain executable.

const (
	InvariantEnvelopeSize        Invariant = "envelope_size"
	InvariantServerSideOwnership Invariant = "server_side_ownership"
	InvariantCrossFlowBinding    Invariant = "cross_flow_binding"
	InvariantProtocolCoexistence Invariant = "protocol_coexistence"
	InvariantCompareAndSwap      Invariant = "compare_and_swap"
	InvariantExpiry              Invariant = "expiry"
	InvariantFormatRejection     Invariant = "format_rejection"
	InvariantSafeRestart         Invariant = "safe_checkpoint_restart"
	InvariantUniformVersion      Invariant = "uniform_version_rollout"
	InvariantFailureAtomicity    Invariant = "failure_atomicity"
)

Invariants are the executable durable browser-session architecture properties.

type Keyspace

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

Keyspace derives non-disclosing Redis Cluster keys from opaque handles.

func NewKeyspace

func NewKeyspace(prefix string, secret []byte) (Keyspace, error)

NewKeyspace creates a keyed-digest namespace for durable browser-session records.

func (Keyspace) Key

func (k Keyspace) Key(owner Owner, reference Reference) (string, error)

Key returns a namespaced record key whose hash tag is shared by one browser session.

type LegacyCookieItem

type LegacyCookieItem struct {
	Name  string
	Key   string
	Owner Owner
}

LegacyCookieItem gives one legacy field exactly one future persistence owner.

func LegacyCookieInventory

func LegacyCookieInventory() []LegacyCookieItem

LegacyCookieInventory returns the complete audited primary-cookie ownership map.

type LogoutIndex

type LogoutIndex struct {
	Record
	Session           Handle
	IdentityReference string
	Account           string
	OIDCClientIDs     []string
}

LogoutIndex is the bounded per-browser list of issued OIDC client sessions. It is current-v1 session-owned state and never contains tokens or browser data.

type Metrics

type Metrics interface {
	Observe(event Event)
}

Metrics records bounded session lifecycle outcomes.

type OIDCFlow

type OIDCFlow struct {
	Record
	Session              Handle
	ParentFlow           Handle
	FlowType             string
	CurrentStep          string
	AuthOutcome          string
	CancelTarget         string
	ReturnTarget         string
	ResumeTarget         string
	CreatedAt            time.Time
	UpdatedAt            time.Time
	PendingMFA           bool
	ClientID             string
	RedirectURI          string
	ResponseType         string
	GrantType            string
	DeviceCode           string
	DeviceUserCodeDigest string
	Scopes               []string
	Resources            []string
	State                string
	Nonce                string
	Prompt               string
	CodeChallenge        string
	CodeChallengeMethod  string
	ConsentChallenge     string
	ConsentDecision      string
	Authenticated        bool
	AssuranceSatisfied   bool
	Issuable             bool
	Issued               bool
	Consumed             bool
}

OIDCFlow identifies one isolated OIDC flow record.

type OIDCFlowRepository

type OIDCFlowRepository interface {
	Repository[OIDCFlow]
}

OIDCFlowRepository persists OIDC request and response state independently from SAML.

type OwnedReference

type OwnedReference struct {
	Owner     Owner
	Reference Reference
}

OwnedReference names a typed child key without exposing its raw handle externally.

type Owner

type Owner string

Owner is the sole future persistence owner of legacy browser-session state.

const (
	OwnerEnvelope         Owner = "envelope"
	OwnerSessionAnchor    Owner = "session_anchor"
	OwnerOIDCFlow         Owner = "oidc_flow"
	OwnerSAMLFlow         Owner = "saml_flow"
	OwnerSelfServiceFlow  Owner = "self_service_flow"
	OwnerEnrollment       Owner = "required_mfa_enrollment"
	OwnerStepUp           Owner = "step_up"
	OwnerWebAuthnCeremony Owner = "webauthn_ceremony"
	OwnerTOTPRecovery     Owner = "totp_recovery"
	OwnerConsent          Owner = "consent_logout_indexes"
	OwnerProtocolSession  Owner = "protocol_session"
	OwnerDeletion         Owner = "deletion"
)

Owner values name the exclusive durable owner for each legacy field.

type RandomHandleGenerator

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

RandomHandleGenerator creates 256-bit opaque handles from a supplied entropy source.

func NewRandomHandleGenerator

func NewRandomHandleGenerator(reader io.Reader) *RandomHandleGenerator

NewRandomHandleGenerator creates a handle generator and defaults nil entropy to crypto/rand.Reader.

func (*RandomHandleGenerator) NewHandle

func (g *RandomHandleGenerator) NewHandle() (Handle, error)

NewHandle returns one URL-safe 256-bit opaque handle.

type Record

type Record struct {
	Handle    Handle
	Revision  Revision
	ExpiresAt time.Time
}

Record is the minimal contract fixture used to keep repository boundaries generic.

type RedisRepository

type RedisRepository[T any] struct {
	// contains filtered or unexported fields
}

RedisRepository persists one typed record family under an exclusive owner namespace.

func (*RedisRepository[T]) Commit

func (r *RedisRepository[T]) Commit(ctx context.Context, request CommitRequest[T]) (Revision, error)

Commit atomically creates or compare-and-swap updates one typed record.

func (*RedisRepository[T]) Consume

func (r *RedisRepository[T]) Consume(ctx context.Context, request DeleteRequest) (Versioned[T], error)

Consume atomically returns and deletes one record at the expected revision. Callers must not expose the value unless this operation succeeds.

func (*RedisRepository[T]) Delete

func (r *RedisRepository[T]) Delete(ctx context.Context, request DeleteRequest) error

Delete removes one record only when the expected revision still matches.

func (*RedisRepository[T]) Load

func (r *RedisRepository[T]) Load(ctx context.Context, reference Reference) (Versioned[T], error)

Load fetches, validates, and decodes one typed record.

type RedisStoreConfig

type RedisStoreConfig struct {
	Prefix        string
	DefaultTTL    time.Duration
	TouchInterval time.Duration
}

RedisStoreConfig defines namespace and write-amortization policy for typed stores.

type RedisStores

type RedisStores struct {
	Session      *RedisRepository[SessionAnchor]
	OIDC         *RedisRepository[OIDCFlow]
	SAML         *RedisRepository[SAMLFlow]
	SelfService  *RedisRepository[SelfServiceFlow]
	Enrollment   *RedisRepository[EnrollmentRecord]
	StepUp       *RedisRepository[StepUpRecord]
	Ceremony     *RedisRepository[CeremonyRecord]
	TOTPRecovery *RedisRepository[TOTPRecoveryRecord]
	Consent      *RedisRepository[ConsentGrant]
	Logout       *RedisRepository[LogoutIndex]
	// contains filtered or unexported fields
}

RedisStores groups separately keyed typed repositories that share one cluster keyspace.

func NewRedisStores

func NewRedisStores(
	client redis.UniversalClient,
	digestSecret []byte,
	clock Clock,
	config RedisStoreConfig,
) (*RedisStores, error)

NewRedisStores creates the complete typed repository set without activating browser paths.

func (*RedisStores) Commit

Commit atomically applies a revision-checked typed mutation set in one Redis Cluster slot.

func (*RedisStores) CommitCeremony

func (s *RedisStores) CommitCeremony(ctx context.Context, request CommitRequest[CeremonyRecord]) (Revision, error)

CommitCeremony atomically indexes and commits one short-lived WebAuthn operation.

func (*RedisStores) CommitEnrollment

func (s *RedisStores) CommitEnrollment(ctx context.Context, request CommitRequest[EnrollmentRecord]) (Revision, error)

CommitEnrollment atomically indexes and commits one required-factor enrollment.

func (*RedisStores) CommitLogoutIndex

func (s *RedisStores) CommitLogoutIndex(ctx context.Context, request CommitRequest[LogoutIndex]) (Revision, error)

CommitLogoutIndex atomically indexes and commits the current-v1 browser logout record.

func (*RedisStores) CommitOIDCFlow

func (s *RedisStores) CommitOIDCFlow(ctx context.Context, request CommitRequest[OIDCFlow]) (Revision, error)

CommitOIDCFlow atomically adds one bounded OIDC index entry and commits its typed child.

func (*RedisStores) CommitSAMLFlow

func (s *RedisStores) CommitSAMLFlow(ctx context.Context, request CommitRequest[SAMLFlow]) (Revision, error)

CommitSAMLFlow atomically adds one bounded SAML index entry and commits its typed child.

func (*RedisStores) CommitSelfServiceFlow

func (s *RedisStores) CommitSelfServiceFlow(
	ctx context.Context,
	request CommitRequest[SelfServiceFlow],
) (Revision, error)

CommitSelfServiceFlow atomically indexes and commits one bounded internal-login flow.

func (*RedisStores) CommitStepUp

func (s *RedisStores) CommitStepUp(ctx context.Context, request CommitRequest[StepUpRecord]) (Revision, error)

CommitStepUp atomically indexes and commits one dynamic-assurance operation.

func (*RedisStores) CommitTOTPRecovery

func (s *RedisStores) CommitTOTPRecovery(ctx context.Context, request CommitRequest[TOTPRecoveryRecord]) (Revision, error)

CommitTOTPRecovery atomically indexes and commits one TOTP or recovery operation.

func (*RedisStores) ConsumeCeremony

func (s *RedisStores) ConsumeCeremony(
	ctx context.Context,
	request DeleteRequest,
) (Versioned[CeremonyRecord], error)

ConsumeCeremony atomically removes a ceremony and its bounded anchor index before returning the payload.

func (*RedisStores) ConsumeOIDCFlow

func (s *RedisStores) ConsumeOIDCFlow(
	ctx context.Context,
	request DeleteRequest,
) (Versioned[OIDCFlow], error)

ConsumeOIDCFlow atomically removes one OIDC flow and its bounded anchor index before returning the payload.

func (*RedisStores) ConsumeSAMLFlow

func (s *RedisStores) ConsumeSAMLFlow(
	ctx context.Context,
	request DeleteRequest,
) (Versioned[SAMLFlow], error)

ConsumeSAMLFlow atomically removes one SAML flow and its bounded anchor index before returning the payload.

func (*RedisStores) ConsumeSelfServiceFlow

func (s *RedisStores) ConsumeSelfServiceFlow(
	ctx context.Context,
	request DeleteRequest,
) (Versioned[SelfServiceFlow], error)

ConsumeSelfServiceFlow atomically removes one internal-login flow and its bounded anchor index.

func (*RedisStores) ConsumeStepUp

func (s *RedisStores) ConsumeStepUp(
	ctx context.Context,
	request DeleteRequest,
) (Versioned[StepUpRecord], error)

ConsumeStepUp atomically removes one terminal step-up and its bounded anchor index.

func (*RedisStores) DeleteEnrollment

func (s *RedisStores) DeleteEnrollment(ctx context.Context, request DeleteRequest) error

DeleteEnrollment atomically removes one enrollment child and its anchor index entry.

func (*RedisStores) DeleteLogoutIndex

func (s *RedisStores) DeleteLogoutIndex(ctx context.Context, request DeleteRequest) error

DeleteLogoutIndex atomically removes one logout index and its anchor entry.

func (*RedisStores) DeleteOIDCFlow

func (s *RedisStores) DeleteOIDCFlow(ctx context.Context, request DeleteRequest) error

DeleteOIDCFlow atomically removes one OIDC child and its anchor index entry.

func (*RedisStores) DeleteSAMLFlow

func (s *RedisStores) DeleteSAMLFlow(ctx context.Context, request DeleteRequest) error

DeleteSAMLFlow atomically removes one SAML child and its anchor index entry.

func (*RedisStores) DeleteSelfServiceFlow

func (s *RedisStores) DeleteSelfServiceFlow(ctx context.Context, request DeleteRequest) error

DeleteSelfServiceFlow atomically removes one internal-login child and its anchor index entry.

func (*RedisStores) DeleteStepUp

func (s *RedisStores) DeleteStepUp(ctx context.Context, request DeleteRequest) error

DeleteStepUp atomically removes one step-up child and its anchor index entry.

func (*RedisStores) DeleteTOTPRecovery

func (s *RedisStores) DeleteTOTPRecovery(ctx context.Context, request DeleteRequest) error

DeleteTOTPRecovery atomically removes one TOTP/recovery child and its anchor index entry.

func (*RedisStores) RevokeSession

func (s *RedisStores) RevokeSession(ctx context.Context, request RevocationRequest) error

RevokeSession writes the anchor tombstone before best-effort idempotent child deletion.

func (*RedisStores) TouchSession

func (s *RedisStores) TouchSession(
	ctx context.Context,
	reference Reference,
	idleTTL time.Duration,
) (bool, error)

TouchSession refreshes idle expiry only after the configured write-amortization window.

type Reference

type Reference struct {
	Session Handle
	Record  Handle
}

Reference binds one record handle to its owning browser session.

func ConsentGrantReference

func ConsentGrantReference(identityReference string, clientID string) (Reference, error)

ConsentGrantReference derives a stable opaque selector for one identity/client consent pair.

type Repository

type Repository[T any] interface {
	Load(ctx context.Context, reference Reference) (Versioned[T], error)
	Commit(ctx context.Context, request CommitRequest[T]) (Revision, error)
	Delete(ctx context.Context, request DeleteRequest) error
}

Repository is the revision-aware persistence boundary for one typed record family.

type Revision

type Revision uint64

Revision is the monotonic compare-and-swap revision of a server-side record.

type RevocationRequest

type RevocationRequest struct {
	Reference        Reference
	ExpectedRevision Revision
	TombstoneTTL     time.Duration
	Children         []OwnedReference
	RejectRevoked    bool
}

RevocationRequest defines a tombstone-first session and child cleanup operation.

type SAMLFlow

type SAMLFlow struct {
	Record
	Session            Handle
	ParentFlow         Handle
	FlowType           string
	CurrentStep        string
	AuthOutcome        string
	CancelTarget       string
	ReturnTarget       string
	CreatedAt          time.Time
	UpdatedAt          time.Time
	PendingMFA         bool
	EntityID           string
	RequestID          string
	RequestDigest      string
	RelayState         string
	Destination        string
	OriginalURL        string
	ResumeTarget       string
	Logout             bool
	Authenticated      bool
	EnrollmentComplete bool
	AssuranceSatisfied bool
	Issuable           bool
	Issued             bool
	Consumed           bool
}

SAMLFlow identifies one isolated SAML flow record.

type SAMLFlowRepository

type SAMLFlowRepository interface {
	Repository[SAMLFlow]
}

SAMLFlowRepository persists SAML request and response state independently from OIDC.

type SelfServiceFlow

type SelfServiceFlow struct {
	FlowType     string
	CurrentStep  string
	AuthOutcome  string
	LoginTarget  string
	ResumeTarget string
	Record
	Session   Handle
	CreatedAt time.Time
	UpdatedAt time.Time
}

SelfServiceFlow identifies one internal primary-login flow for the MFA portal.

type SelfServiceFlowRepository

type SelfServiceFlowRepository interface {
	Repository[SelfServiceFlow]
}

SelfServiceFlowRepository persists internal browser-login state independently from external protocols.

type SessionAnchor

type SessionAnchor struct {
	Record
	SchemaVersion        uint8
	CreatedAt            time.Time
	IdleExpiresAt        time.Time
	AbsoluteExpiresAt    time.Time
	LastTouchedAt        time.Time
	Authenticated        bool
	IdentityReference    string
	Identity             IdentitySummary
	BackendAffinity      BackendAffinitySummary
	MFAIdentityReference string
	MFAIdentity          IdentitySummary
	MFABackendAffinity   BackendAffinitySummary
	Assurance            AssuranceSummary
	RotatedFrom          Handle
	OIDCFlows            []Handle
	SAMLFlows            []Handle
	SelfServiceFlows     []Handle
	Enrollments          []Handle
	StepUps              []Handle
	Ceremonies           []Handle
	TOTPRecovery         []Handle
	LogoutIndexes        []Handle
	Revoked              bool
	Tombstone            bool
}

SessionAnchor is the bounded server-side identity and active-flow index for one browser session.

type SessionRepository

type SessionRepository interface {
	Repository[SessionAnchor]
}

SessionRepository persists the browser session anchor independently from protocol flows.

type StepUpRecord

type StepUpRecord struct {
	Record
	Session                  Handle
	Flow                     Handle
	AuthOutcome              string
	PendingIdentityReference string
	PendingIdentity          IdentitySummary
	PendingBackendAffinity   BackendAffinitySummary
	SelfServiceOperation     string
	SelfServiceCredentialID  string
	SelfServiceDeviceName    string
	RequestedLevel           int
	SupportedMethods         []string
	MethodLevels             map[string]int
	ProofMethod              string
	CompletedAt              time.Time
	FreshUntil               time.Time
	Scope                    string
	Completed                bool
}

StepUpRecord owns one dynamic assurance or self-service proof operation.

type TOTPRecoveryRecord

type TOTPRecoveryRecord struct {
	Record
	Session           Handle
	Flow              Handle
	AccountReference  string
	IdentityReference string
	OperationID       string
	Kind              string
	PendingMaterial   []byte
	RecoveryCodes     []string
	Generated         bool
	Saved             bool
	RetryCount        uint8
}

TOTPRecoveryRecord owns short-lived TOTP or recovery-code operation state.

type Transaction

type Transaction interface {
	Commit(ctx context.Context, request TransactionRequest) (TransactionReceipt, error)
}

Transaction begins one atomic multi-record mutation.

type TransactionFactory

type TransactionFactory interface {
	Begin(ctx context.Context, session Handle) (Transaction, error)
}

TransactionFactory creates transactions bound to one browser session anchor.

type TransactionReceipt

type TransactionReceipt struct {
	Revision Revision
}

TransactionReceipt reports the committed anchor revision.

type TransactionRequest

type TransactionRequest struct {
	Session      *CommitRequest[SessionAnchor]
	OIDC         []CommitRequest[OIDCFlow]
	SAML         []CommitRequest[SAMLFlow]
	SelfService  []CommitRequest[SelfServiceFlow]
	Enrollment   []CommitRequest[EnrollmentRecord]
	StepUp       []CommitRequest[StepUpRecord]
	Ceremony     []CommitRequest[CeremonyRecord]
	TOTPRecovery []CommitRequest[TOTPRecoveryRecord]
	Logout       []CommitRequest[LogoutIndex]
}

TransactionRequest groups typed writes and deletions that must become visible together.

type Versioned

type Versioned[T any] struct {
	Value    T
	Revision Revision
}

Versioned is one typed record together with its compare-and-swap revision.

Jump to

Keyboard shortcuts

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