cookie

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: 26 Imported by: 0

Documentation

Overview

Package cookie provides secure encrypted cookie management for storing sensitive session data in a single encrypted browser cookie.

Index

Constants

View Source
const (
	// CurrentEnvelopeVersion is the sole browser format accepted by this binary.
	CurrentEnvelopeVersion uint8 = 1
	// EnvelopeTargetBytes is the preferred maximum encoded envelope size.
	EnvelopeTargetBytes = 256
	// EnvelopeHardLimitBytes is the absolute encoded envelope ceiling.
	EnvelopeHardLimitBytes = 512
)

Variables

View Source
var (
	// ErrInvalidCookie indicates the cookie value is malformed or tampered.
	ErrInvalidCookie = errors.New("cookie: invalid or tampered cookie")

	// ErrExpiredCookie indicates the cookie has exceeded its maximum age.
	ErrExpiredCookie = errors.New("cookie: expired cookie")
)
View Source
var (
	// ErrEnvelopeRejected classifies malformed, legacy, tampered, or inconsistent browser formats.
	ErrEnvelopeRejected = errors.New("cookie: canonical envelope rejected")
	// ErrEnvelopeConfiguration classifies startup configuration that cannot safely encode the canonical format.
	ErrEnvelopeConfiguration = errors.New("cookie: invalid canonical envelope configuration")
)

Functions

func CanonicalMiddleware

func CanonicalMiddleware(runtime *CanonicalRuntime, mode CanonicalMode) gin.HandlerFunc

CanonicalMiddleware composes the sole envelope runtime with an explicit route checkpoint.

func Middleware

func Middleware(secret []byte, cfg config.File, env config.Environment) gin.HandlerFunc

Middleware creates a gin middleware that loads the secure data cookie at the start of the request and saves it after the handler chain completes. The CookieManager is stored in the gin.Context under CtxSecureDataKey.

func SetAuthResult

func SetAuthResult(mgr Manager, username string, result definitions.AuthResult)

SetAuthResult stores the authentication result together with an HMAC integrity tag that binds the result to the username and a timestamp. This prevents tampering with the auth_result value even if the outer cookie encryption were somehow bypassed.

func SetCanonicalSession

func SetCanonicalSession(ctx *gin.Context, session *CanonicalSession)

SetCanonicalSession replaces the request-scoped session after a durable handle rotation.

func VerifyAuthResult

func VerifyAuthResult(mgr Manager, username string) (definitions.AuthResult, bool)

VerifyAuthResult reads the auth_result from the cookie and verifies its HMAC integrity tag. Returns the AuthResult and true only if:

  • mgr is non-nil
  • auth_result key exists
  • auth_result_hmac key exists and is valid
  • the HMAC matches the stored username + result + timestamp

On any failure (missing data, wrong HMAC, nil mgr), returns AuthResultFail and false. This implements default-deny: the caller must not grant access unless this returns true.

Types

type CanonicalMode

type CanonicalMode uint8

CanonicalMode defines whether a route validates a fresh protocol request or continues bound state.

const (
	// CanonicalProtocolEntry may create a fresh anchor after purging a rejected or absent representation.
	CanonicalProtocolEntry CanonicalMode = iota + 1
	// CanonicalSelfServiceEntry may create a fresh anonymous anchor for the bounded MFA portal entry.
	CanonicalSelfServiceEntry
	// CanonicalLogoutEntry accepts an absent or rejected envelope so logout remains idempotent.
	CanonicalLogoutEntry
	// CanonicalContinuation requires an already valid canonical anchor and never reconstructs state.
	CanonicalContinuation
)

type CanonicalRuntime

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

CanonicalRuntime owns the sole browser envelope and server-side anchor lifecycle.

func NewCanonicalRuntime

func NewCanonicalRuntime(
	secret []byte,
	keyEpoch uint16,
	client redis.UniversalClient,
	prefix string,
	clock sessionstate.Clock,
	generator sessionstate.HandleGenerator,
	secure bool,
) (*CanonicalRuntime, error)

NewCanonicalRuntime validates the envelope and typed Redis store configuration.

func (*CanonicalRuntime) Create

func (r *CanonicalRuntime) Create(
	ctx context.Context,
	writer http.ResponseWriter,
	remember bool,
) (*CanonicalSession, error)

Create commits a fresh anchor before emitting its canonical envelope.

func (*CanonicalRuntime) Open

func (r *CanonicalRuntime) Open(ctx context.Context, request *http.Request) (*CanonicalSession, error)

Open validates exactly one canonical envelope and loads its live anchor.

func (*CanonicalRuntime) PurgeBrowser

func (r *CanonicalRuntime) PurgeBrowser(writer http.ResponseWriter)

PurgeBrowser deletes every pre-cutover and canonical browser representation.

type CanonicalSession

type CanonicalSession struct {
	Handle sessionstate.Handle
	Anchor sessionstate.Versioned[sessionstate.SessionAnchor]
	Stores *sessionstate.RedisStores
	// contains filtered or unexported fields
}

CanonicalSession is one loaded anchor and its exclusively typed repositories.

func GetCanonicalSession

func GetCanonicalSession(ctx *gin.Context) *CanonicalSession

GetCanonicalSession returns the request-scoped typed browser session.

func (*CanonicalSession) Assurance

func (s *CanonicalSession) Assurance(now time.Time) (SessionAssurance, bool)

Assurance returns only a complete, currently live assurance summary.

func (*CanonicalSession) BackendAffinity

func (s *CanonicalSession) BackendAffinity() (SessionBackendAffinity, bool)

BackendAffinity returns only a complete authority capability held in the server-side anchor.

func (*CanonicalSession) CommitAssurance

func (s *CanonicalSession) CommitAssurance(ctx context.Context, proof SessionAssurance) error

CommitAssurance atomically publishes one live MFA proof through the authenticated anchor revision.

func (*CanonicalSession) CommitIdentity

func (s *CanonicalSession) CommitIdentity(ctx context.Context, update IdentityUpdate) error

CommitIdentity atomically publishes one successful identity binding through the anchor revision.

func (*CanonicalSession) CompleteLogin

func (s *CanonicalSession) CompleteLogin(
	ctx context.Context,
	writer http.ResponseWriter,
	input LoginCompletionInput,
) (*CanonicalSession, error)

CompleteLogin rotates the canonical handle and publishes identity, protocol, and child state before the envelope.

func (*CanonicalSession) CompleteStepUp

func (s *CanonicalSession) CompleteStepUp(
	ctx context.Context,
	handle sessionstate.Handle,
	method string,
	freshness time.Duration,
) (StepUpCompletion, error)

CompleteStepUp atomically marks one typed challenge complete and publishes its session assurance.

func (*CanonicalSession) ConsumeFailLatchedStepUp

func (s *CanonicalSession) ConsumeFailLatchedStepUp(
	ctx context.Context,
	handle sessionstate.Handle,
	method string,
) (StepUpCompletion, error)

ConsumeFailLatchedStepUp terminalizes one delayed-response proof without authenticating the browser session.

func (*CanonicalSession) EvaluationTime

func (s *CanonicalSession) EvaluationTime() time.Time

EvaluationTime returns the session runtime clock used for TTL and assurance decisions.

func (*CanonicalSession) Identity

func (s *CanonicalSession) Identity() (SessionIdentity, bool)

Identity returns a consistent authenticated identity binding from the session anchor.

func (*CanonicalSession) MFABackendAffinity

func (s *CanonicalSession) MFABackendAffinity() (SessionBackendAffinity, bool)

MFABackendAffinity returns the capability bound to the assurance identity.

func (*CanonicalSession) MFAIdentity

func (s *CanonicalSession) MFAIdentity() (SessionIdentity, bool)

MFAIdentity returns the account whose factor proves assurance for this session.

func (*CanonicalSession) OIDCLogoutContext

func (s *CanonicalSession) OIDCLogoutContext(ctx context.Context) (OIDCLogoutContext, error)

OIDCLogoutContext loads only the current session's typed logout index.

func (*CanonicalSession) PurgeBrowser

func (s *CanonicalSession) PurgeBrowser(writer http.ResponseWriter)

PurgeBrowser removes the canonical browser envelope after an explicit session-ending action.

func (*CanonicalSession) RecordOIDCClient

func (s *CanonicalSession) RecordOIDCClient(
	ctx context.Context,
	identity SessionIdentity,
	clientID string,
) error

RecordOIDCClient records one successfully issued OIDC client session without tokens.

func (*CanonicalSession) RefreshAnchor

func (s *CanonicalSession) RefreshAnchor(ctx context.Context) error

RefreshAnchor reloads the current typed anchor after an indexed child mutation.

func (*CanonicalSession) RestartLogin

func (s *CanonicalSession) RestartLogin(ctx context.Context, writer http.ResponseWriter) (*CanonicalSession, error)

RestartLogin replaces browser SSO and its pending operations with an anonymous session. It leaves application tokens untouched and publishes no replacement if revocation fails.

func (*CanonicalSession) Revoke

func (s *CanonicalSession) Revoke(ctx context.Context, writer http.ResponseWriter) error

Revoke tombstones the canonical anchor before deleting its indexed current-v1 children. Browser representations are purged even when Redis revocation fails.

type Envelope

type Envelope struct {
	Version  uint8
	Session  sessionstate.Handle
	KeyEpoch uint16
	Flags    uint8
}

Envelope is the complete browser-held session representation.

type EnvelopeCodec

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

EnvelopeCodec authenticates, encrypts, and strictly validates one envelope version.

func NewEnvelopeCodec

func NewEnvelopeCodec(secret []byte, keyEpoch uint16) (*EnvelopeCodec, error)

NewEnvelopeCodec creates the sole-version codec for one configured key epoch.

func (*EnvelopeCodec) Decode

func (c *EnvelopeCodec) Decode(name string, encoded string) (Envelope, error)

Decode accepts only the current version, configured epoch, and canonical handle format.

func (*EnvelopeCodec) Encode

func (c *EnvelopeCodec) Encode(name string, envelope Envelope) (string, error)

Encode validates and encrypts the canonical browser envelope.

type IdentityUpdate

type IdentityUpdate struct {
	Reference          string
	Account            string
	Subject            string
	DisplayName        string
	Protocol           string
	BackendAffinity    *SessionBackendAffinity
	MFAIdentity        *SessionIdentity
	MFABackendAffinity *SessionBackendAffinity
}

IdentityUpdate is the complete successful-authentication projection committed to the anchor.

type LoginCompletionInput

type LoginCompletionInput struct {
	Identity    IdentityUpdate
	Flow        sessionstate.Handle
	Protocol    string
	NextStep    string
	RememberTTL time.Duration
}

LoginCompletionInput is the complete durable state transition for one successful primary login.

type Manager

type Manager interface {
	// Set stores a key-value pair in the cookie data.
	Set(key string, value any)

	// Get retrieves a value by key from the cookie data.
	// Returns nil and false if the key does not exist.
	Get(key string) (any, bool)

	// Delete removes a key from the cookie data.
	Delete(key string)

	// Clear removes all data from the cookie.
	Clear()

	// Save persists the encrypted cookie to the response.
	Save(ctx *gin.Context) error

	// Load reads and decrypts the cookie from the request.
	// If the cookie does not exist or cannot be decoded, it initializes empty data.
	Load(ctx *gin.Context) error

	// GetString retrieves a string value by key, returning the default if not found or wrong type.
	GetString(key string, defaultValue string) string

	// GetInt retrieves an int value by key, returning the default if not found or wrong type.
	GetInt(key string, defaultValue int) int

	// GetInt64 retrieves an int64 value by key, returning the default if not found or wrong type.
	GetInt64(key string, defaultValue int64) int64

	// GetUint8 retrieves a uint8 value by key, returning the default if not found or wrong type.
	GetUint8(key string, defaultValue uint8) uint8

	// GetBool retrieves a bool value by key, returning the default if not found or wrong type.
	GetBool(key string, defaultValue bool) bool

	// GetStringSlice retrieves a []string value by key, returning the default if not found or wrong type.
	GetStringSlice(key string, defaultValue []string) []string

	// GetDuration retrieves a time.Duration value by key, returning the default if not found or wrong type.
	GetDuration(key string, defaultValue time.Duration) time.Duration

	// GetBytes retrieves a []byte value by key, returning the default if not found or wrong type.
	GetBytes(key string, defaultValue []byte) []byte

	// Debug logs the current cookie data with sensitive values masked.
	Debug(ctx *gin.Context, logger *slog.Logger, msg string)

	// HasKey checks if a key exists in the cookie data.
	HasKey(key string) bool

	// SetMaxAge sets the maximum age of the cookie in seconds.
	SetMaxAge(maxAge int)

	// ComputeHMAC returns an HMAC-SHA256 tag for the given data using the codec's auth key.
	// Used for defense-in-depth integrity checks on security-critical session values.
	ComputeHMAC(data []byte) []byte
}

Manager defines the interface for secure cookie storage operations. All session data is stored in a single encrypted cookie.

func GetManager

func GetManager(ctx *gin.Context) Manager

GetManager retrieves the CookieManager from the gin.Context. Returns nil if the middleware was not applied.

func MustGetManager

func MustGetManager(ctx *gin.Context) Manager

MustGetManager retrieves the CookieManager from the gin.Context. Panics if the middleware was not applied.

type OIDCLogoutContext

type OIDCLogoutContext struct {
	Identity  SessionIdentity
	ClientIDs []string
}

OIDCLogoutContext is the bounded typed identity/client projection used by logout.

type SecureCodec

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

SecureCodec provides authenticated encryption for cookie values using ChaCha20-Poly1305 for encryption and HMAC-SHA256 for name binding.

The encoding format is: base64(hmac(16 bytes) + timestamp(8 bytes) + nonce(12 bytes) + ciphertext)

Key derivation: - encKey = SHA256(secret)[:32] used for ChaCha20-Poly1305 - authKey = SHA256(secret + "_auth")[:32] used for HMAC

func NewSecureCodec

func NewSecureCodec(secret []byte) *SecureCodec

NewSecureCodec creates a new codec from a secret byte slice. The secret is used to derive encryption and authentication keys via SHA256.

func (*SecureCodec) Decode

func (c *SecureCodec) Decode(name string, encoded string, dst any) error

Decode decrypts and deserializes the cookie value. Returns ErrInvalidCookie if decryption fails or HMAC verification fails. Returns ErrExpiredCookie if the timestamp is older than maxAge.

func (*SecureCodec) Encode

func (c *SecureCodec) Encode(name string, value any) (string, error)

Encode serializes and encrypts the value, binding it to the cookie name. Returns a base64-encoded string suitable for HTTP cookies.

func (*SecureCodec) SetMaxAge

func (c *SecureCodec) SetMaxAge(maxAge int)

SetMaxAge sets the maximum age in seconds for encoded cookies. Use 0 to disable timestamp validation.

type SecureManager

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

SecureManager implements Manager using ChaCha20-Poly1305 for encryption.

func NewSecureManager

func NewSecureManager(secret []byte, cookieName string, cfg config.File, env config.Environment) *SecureManager

NewSecureManager creates a new encrypted cookie manager. The secret is used to derive encryption and authentication keys via SHA256. The cfg parameter provides access to debug module configuration.

func (*SecureManager) Clear

func (m *SecureManager) Clear()

Clear removes all data from the cookie.

func (*SecureManager) ComputeHMAC

func (m *SecureManager) ComputeHMAC(data []byte) []byte

ComputeHMAC returns an HMAC-SHA256 tag for the given data using the codec's auth key.

func (*SecureManager) Debug

func (m *SecureManager) Debug(ctx *gin.Context, logger *slog.Logger, msg string)

Debug logs the current cookie data with sensitive values masked.

func (*SecureManager) Delete

func (m *SecureManager) Delete(key string)

Delete removes a key from the cookie data.

func (*SecureManager) Get

func (m *SecureManager) Get(key string) (any, bool)

Get retrieves a value by key from the cookie data.

func (*SecureManager) GetBool

func (m *SecureManager) GetBool(key string, defaultValue bool) bool

GetBool retrieves a bool value by key, returning the default if not found or wrong type.

func (*SecureManager) GetBytes

func (m *SecureManager) GetBytes(key string, defaultValue []byte) []byte

GetBytes retrieves a []byte value by key, returning the default if not found or wrong type.

func (*SecureManager) GetDuration

func (m *SecureManager) GetDuration(key string, defaultValue time.Duration) time.Duration

GetDuration retrieves a time.Duration value by key, returning the default if not found or wrong type.

func (*SecureManager) GetInt

func (m *SecureManager) GetInt(key string, defaultValue int) int

GetInt retrieves an int value by key, returning the default if not found or wrong type. Returns defaultValue if the stored int64 value would overflow the int type.

func (*SecureManager) GetInt64

func (m *SecureManager) GetInt64(key string, defaultValue int64) int64

GetInt64 retrieves an int64 value by key, returning the default if not found or wrong type.

func (*SecureManager) GetString

func (m *SecureManager) GetString(key string, defaultValue string) string

GetString retrieves a string value by key, returning the default if not found or wrong type.

func (*SecureManager) GetStringSlice

func (m *SecureManager) GetStringSlice(key string, defaultValue []string) []string

GetStringSlice retrieves a []string value by key, returning the default if not found or wrong type.

func (*SecureManager) GetUint8

func (m *SecureManager) GetUint8(key string, defaultValue uint8) uint8

GetUint8 retrieves a uint8 value by key, returning the default if not found or wrong type.

func (*SecureManager) HasKey

func (m *SecureManager) HasKey(key string) bool

HasKey checks if a key exists in the cookie data.

func (*SecureManager) Keys

func (m *SecureManager) Keys() []string

Keys returns all keys currently stored in the cookie.

func (*SecureManager) Load

func (m *SecureManager) Load(ctx *gin.Context) error

Load reads and decrypts the cookie from the request.

func (*SecureManager) Save

func (m *SecureManager) Save(ctx *gin.Context) error

Save persists the encrypted cookie to the response.

func (*SecureManager) Set

func (m *SecureManager) Set(key string, value any)

Set stores a key-value pair in the cookie data.

func (*SecureManager) SetMaxAge

func (m *SecureManager) SetMaxAge(maxAge int)

SetMaxAge sets the maximum age of the cookie in seconds. Use 0 for session cookies, negative values to delete. This also updates the codec's maxAge to ensure the internal timestamp validation is consistent with the browser cookie lifetime.

func (*SecureManager) SetPath

func (m *SecureManager) SetPath(path string)

SetPath sets the cookie path.

type SessionAssurance

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

SessionAssurance is the bounded, non-secret MFA proof shared across protocol flows.

type SessionBackendAffinity

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

SessionBackendAffinity is the server-side authority capability for follow-up identity operations.

type SessionIdentity

type SessionIdentity struct {
	Reference   string
	Account     string
	Subject     string
	DisplayName string
	Protocol    string
}

SessionIdentity is the stable identity binding exposed to browser-flow callers.

type StepUpCompletion

type StepUpCompletion struct {
	Handle               sessionstate.Handle
	Flow                 sessionstate.Handle
	SelfServiceOperation string
	Method               string
	Scope                string
	Level                int
	ProvenAt             time.Time
	FreshUntil           time.Time
}

StepUpCompletion identifies the parent protocol flow released by one committed proof.

type WebAuthnCeremonyReferenceState

type WebAuthnCeremonyReferenceState struct {
	Dedicated string
	Legacy    string
}

WebAuthnCeremonyReferenceState is the browser's dedicated reference plus any legacy primary-cookie remnant that must only be inspected for cleanup.

type WebAuthnCeremonyReferenceStateManager

type WebAuthnCeremonyReferenceStateManager interface {
	WebAuthnCeremonyReferenceState() WebAuthnCeremonyReferenceState
}

WebAuthnCeremonyReferenceStateManager exposes both browser representations without making the legacy representation available through Manager.Get.

Jump to

Keyboard shortcuts

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