Documentation
¶
Overview ¶
Package cookie provides secure encrypted cookie management for storing sensitive session data in a single encrypted browser cookie.
Index ¶
- Constants
- Variables
- func CanonicalMiddleware(runtime *CanonicalRuntime, mode CanonicalMode) gin.HandlerFunc
- func Middleware(secret []byte, cfg config.File, env config.Environment) gin.HandlerFunc
- func SetAuthResult(mgr Manager, username string, result definitions.AuthResult)
- func SetCanonicalSession(ctx *gin.Context, session *CanonicalSession)
- func VerifyAuthResult(mgr Manager, username string) (definitions.AuthResult, bool)
- type CanonicalMode
- type CanonicalRuntime
- type CanonicalSession
- func (s *CanonicalSession) Assurance(now time.Time) (SessionAssurance, bool)
- func (s *CanonicalSession) BackendAffinity() (SessionBackendAffinity, bool)
- func (s *CanonicalSession) CommitAssurance(ctx context.Context, proof SessionAssurance) error
- func (s *CanonicalSession) CommitIdentity(ctx context.Context, update IdentityUpdate) error
- func (s *CanonicalSession) CompleteLogin(ctx context.Context, writer http.ResponseWriter, input LoginCompletionInput) (*CanonicalSession, error)
- func (s *CanonicalSession) CompleteStepUp(ctx context.Context, handle sessionstate.Handle, method string, ...) (StepUpCompletion, error)
- func (s *CanonicalSession) ConsumeFailLatchedStepUp(ctx context.Context, handle sessionstate.Handle, method string) (StepUpCompletion, error)
- func (s *CanonicalSession) EvaluationTime() time.Time
- func (s *CanonicalSession) Identity() (SessionIdentity, bool)
- func (s *CanonicalSession) MFABackendAffinity() (SessionBackendAffinity, bool)
- func (s *CanonicalSession) MFAIdentity() (SessionIdentity, bool)
- func (s *CanonicalSession) OIDCLogoutContext(ctx context.Context) (OIDCLogoutContext, error)
- func (s *CanonicalSession) PurgeBrowser(writer http.ResponseWriter)
- func (s *CanonicalSession) RecordOIDCClient(ctx context.Context, identity SessionIdentity, clientID string) error
- func (s *CanonicalSession) RefreshAnchor(ctx context.Context) error
- func (s *CanonicalSession) RestartLogin(ctx context.Context, writer http.ResponseWriter) (*CanonicalSession, error)
- func (s *CanonicalSession) Revoke(ctx context.Context, writer http.ResponseWriter) error
- type Envelope
- type EnvelopeCodec
- type IdentityUpdate
- type LoginCompletionInput
- type Manager
- type OIDCLogoutContext
- type SecureCodec
- type SecureManager
- func (m *SecureManager) Clear()
- func (m *SecureManager) ComputeHMAC(data []byte) []byte
- func (m *SecureManager) Debug(ctx *gin.Context, logger *slog.Logger, msg string)
- func (m *SecureManager) Delete(key string)
- func (m *SecureManager) Get(key string) (any, bool)
- func (m *SecureManager) GetBool(key string, defaultValue bool) bool
- func (m *SecureManager) GetBytes(key string, defaultValue []byte) []byte
- func (m *SecureManager) GetDuration(key string, defaultValue time.Duration) time.Duration
- func (m *SecureManager) GetInt(key string, defaultValue int) int
- func (m *SecureManager) GetInt64(key string, defaultValue int64) int64
- func (m *SecureManager) GetString(key string, defaultValue string) string
- func (m *SecureManager) GetStringSlice(key string, defaultValue []string) []string
- func (m *SecureManager) GetUint8(key string, defaultValue uint8) uint8
- func (m *SecureManager) HasKey(key string) bool
- func (m *SecureManager) Keys() []string
- func (m *SecureManager) Load(ctx *gin.Context) error
- func (m *SecureManager) Save(ctx *gin.Context) error
- func (m *SecureManager) Set(key string, value any)
- func (m *SecureManager) SetMaxAge(maxAge int)
- func (m *SecureManager) SetPath(path string)
- type SessionAssurance
- type SessionBackendAffinity
- type SessionIdentity
- type StepUpCompletion
- type WebAuthnCeremonyReferenceState
- type WebAuthnCeremonyReferenceStateManager
Constants ¶
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 ¶
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") )
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.
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 ¶
GetManager retrieves the CookieManager from the gin.Context. Returns nil if the middleware was not applied.
func MustGetManager ¶
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) 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 ¶
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 ¶
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.