memory

package
v0.2.161 Latest Latest
Warning

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

Go to latest
Published: May 27, 2026 License: Apache-2.0 Imports: 17 Imported by: 1

Documentation

Overview

Package memory provides an in-memory implementation of the OAuth storage interfaces.

This package implements TokenStore, ClientStore, and FlowStore interfaces using Go's built-in maps with mutex protection for thread safety. It is suitable for development, testing, and single-instance deployments where persistence is not required.

Features:

  • Thread-safe operations using sync.RWMutex
  • Automatic cleanup of expired tokens, codes, and flows
  • Configurable cleanup intervals
  • Token encryption support via Encryptor
  • Audit logging support via Auditor

For production deployments requiring persistence or multi-instance deployments, use the storage/valkey package instead.

Example usage:

// Plain store (no encryption, default 1m cleanup interval):
store := memory.New()
defer store.Stop()

// With encryption at rest and a custom cleanup interval:
key, _ := security.GenerateKey()
enc, _ := security.NewEncryptor(key)
store := memory.New(memory.WithEncryptor(enc), memory.WithCleanupInterval(30*time.Second))
defer store.Stop()

// Use store for TokenStore, ClientStore, and FlowStore interfaces:
server, _ := oauth.NewServer(provider, store, store, store, config, logger)

Package memory provides an in-memory implementation of all storage interfaces. It is suitable for development, testing, and single-instance deployments.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Option added in v0.2.160

type Option func(*Store)

Option configures a Store at construction time.

func WithCleanupInterval added in v0.2.160

func WithCleanupInterval(d time.Duration) Option

WithCleanupInterval sets the background cleanup tick interval. Values ≤ 0 are clamped to 1 minute.

func WithEncryptor added in v0.2.160

func WithEncryptor(enc *security.Encryptor) Option

WithEncryptor enables AES-256-GCM encryption at rest for all stored tokens. Encryption is optional; omit to store tokens in plaintext.

func WithInstrumentation added in v0.2.160

func WithInstrumentation(inst *instrumentation.Instrumentation) Option

WithInstrumentation wires OpenTelemetry tracing and metrics into the store.

func WithLogger added in v0.2.160

func WithLogger(logger *slog.Logger) Option

WithLogger replaces the default slog.Default() logger.

func WithRevokedFamilyRetentionDays added in v0.2.160

func WithRevokedFamilyRetentionDays(days int64) Option

WithRevokedFamilyRetentionDays sets how long revoked token family metadata is kept for security forensics. Default is 90 days.

type RefreshTokenFamily

type RefreshTokenFamily struct {
	FamilyID   string    // Unique identifier for this token family
	UserID     string    // User who owns this family
	ClientID   string    // Client who owns this family
	Generation int       // Increments with each rotation
	IssuedAt   time.Time // When this generation was issued
	Revoked    bool      // True if family has been revoked due to reuse detection
	RevokedAt  time.Time // When this family was revoked (for cleanup purposes)
}

RefreshTokenFamily tracks a family of refresh tokens for reuse detection (OAuth 2.1)

type Store

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

Store is an in-memory implementation of all storage interfaces. It implements TokenStore, ClientStore, FlowStore, RefreshTokenFamilyStore, and TokenRevocationStore.

func New

func New(opts ...Option) *Store

New creates a new in-memory store. All dependencies (encryptor, instrumentation, logger) are supplied at construction via options and are immutable afterward.

func (*Store) AtomicCheckAndMarkAuthCodeUsed added in v0.1.11

func (s *Store) AtomicCheckAndMarkAuthCodeUsed(_ context.Context, code string) (*storage.AuthorizationCode, error)

AtomicCheckAndMarkAuthCodeUsed atomically checks if a code is unused and marks it as used. This prevents race conditions in authorization code reuse detection. Returns the auth code if successful, or an error if code is already used.

SECURITY: This operation is atomic - only ONE concurrent request can succeed. All other concurrent requests will receive an "already used" error.

IMPORTANT: The authCode is ONLY returned on reuse errors (Used=true) to enable detection and revocation. For other errors (not found, expired), nil is returned to prevent information leakage.

func (*Store) AtomicGetAndDeleteRefreshToken added in v0.1.11

func (s *Store) AtomicGetAndDeleteRefreshToken(_ context.Context, refreshToken string) (string, string, *oauth2.Token, error)

AtomicGetAndDeleteRefreshToken atomically retrieves and deletes a refresh token. This prevents race conditions in refresh token rotation and reuse detection. Returns the userID, clientID, and provider token if successful.

SECURITY: This operation is atomic - only ONE concurrent request can succeed. All other concurrent requests will receive a "token not found" error. SECURITY: Returns clientID for client binding validation per OAuth 2.1 Section 6.

func (*Store) CheckIPLimit

func (s *Store) CheckIPLimit(_ context.Context, ip string, maxClientsPerIP int) error

CheckIPLimit checks if an IP has reached the client registration limit

func (*Store) DeleteAuthorizationCode

func (s *Store) DeleteAuthorizationCode(_ context.Context, code string) error

DeleteAuthorizationCode removes an authorization code

func (*Store) DeleteAuthorizationState

func (s *Store) DeleteAuthorizationState(_ context.Context, stateID string) error

DeleteAuthorizationState removes an authorization state Removes both client state and provider state entries

func (*Store) DeleteClient added in v0.2.145

func (s *Store) DeleteClient(_ context.Context, clientID string) error

DeleteClient removes a registered client by ID.

func (*Store) DeleteRefreshToken

func (s *Store) DeleteRefreshToken(_ context.Context, refreshToken string) error

DeleteRefreshToken removes a refresh token (used for rotation)

func (*Store) DeleteToken

func (s *Store) DeleteToken(ctx context.Context, userID string) error

DeleteToken removes a token for a user

func (*Store) GetActiveRefreshTokenByFamily added in v0.2.122

func (s *Store) GetActiveRefreshTokenByFamily(_ context.Context, familyID string) (refreshToken, clientID string, err error)

GetActiveRefreshTokenByFamily returns the most recent (highest generation) non-revoked refresh token for the family along with the owning client ID (storage.ActiveRefreshTokenByFamilyStore). Linear scan, same shape as GetRefreshTokenFamilyByID.

Returns ErrRefreshTokenFamilyNotFound when no entry matches at all, or ErrRefreshTokenFamilyRevoked when entries exist but every member is revoked.

func (*Store) GetAuthorizationCode

func (s *Store) GetAuthorizationCode(_ context.Context, code string) (*storage.AuthorizationCode, error)

GetAuthorizationCode retrieves an authorization code without modifying it. The code is kept marked as "Used" to detect reuse attempts (OAuth 2.1 requirement). Expired/used codes are cleaned up by the background cleanup goroutine.

NOTE: For actual code exchange, use AtomicCheckAndMarkAuthCodeUsed instead to prevent race conditions.

func (*Store) GetAuthorizationState

func (s *Store) GetAuthorizationState(_ context.Context, stateID string) (*storage.AuthorizationState, error)

GetAuthorizationState retrieves an authorization state by client state

func (*Store) GetAuthorizationStateByProviderState

func (s *Store) GetAuthorizationStateByProviderState(_ context.Context, providerState string) (*storage.AuthorizationState, error)

GetAuthorizationStateByProviderState retrieves an authorization state by provider state This is used during provider callback validation (separate from client state)

func (*Store) GetClient

func (s *Store) GetClient(ctx context.Context, clientID string) (*storage.Client, error)

GetClient retrieves a client by ID

func (*Store) GetRefreshTokenFamily

func (s *Store) GetRefreshTokenFamily(_ context.Context, refreshToken string) (*storage.RefreshTokenFamilyMetadata, error)

GetRefreshTokenFamily retrieves family metadata for a refresh token

func (*Store) GetRefreshTokenFamilyByID added in v0.2.120

func (s *Store) GetRefreshTokenFamilyByID(_ context.Context, familyID string) (*storage.RefreshTokenFamilyMetadata, error)

GetRefreshTokenFamilyByID returns family metadata indexed by family ID (storage.RefreshTokenFamilyByIDStore). The internal map is keyed by refresh token, so this is a linear scan over an entry count bounded by hardMaxFamilyMetadataEntries (50000). Cheap in practice; if it ever shows up in a profile, add a parallel familyID -> refreshToken index.

func (*Store) GetRefreshTokenInfo

func (s *Store) GetRefreshTokenInfo(_ context.Context, refreshToken string) (string, error)

GetRefreshTokenInfo retrieves the user ID for a refresh token Returns error if token is not found or expired (with clock skew grace)

func (*Store) GetToken

func (s *Store) GetToken(ctx context.Context, userID string) (*oauth2.Token, error)

GetToken retrieves an oauth2.Token for a user and decrypts if necessary

func (*Store) GetTokenMetadata added in v0.1.34

func (s *Store) GetTokenMetadata(tokenID string) (*storage.TokenMetadata, error)

GetTokenMetadata retrieves metadata for a token (including RFC 8707 audience)

func (*Store) GetTokensByUserClient added in v0.1.9

func (s *Store) GetTokensByUserClient(_ context.Context, userID, clientID string) ([]string, error)

GetTokensByUserClient retrieves all token IDs for a user+client combination. This is primarily for testing and debugging purposes.

func (*Store) GetUserInfo

func (s *Store) GetUserInfo(ctx context.Context, userID string) (*providers.UserInfo, error)

GetUserInfo retrieves user information

func (*Store) IsJTIRevoked added in v0.2.120

func (s *Store) IsJTIRevoked(_ context.Context, jti string) (bool, error)

IsJTIRevoked implements storage.RevokedTokenStore.

func (*Store) ListClients

func (s *Store) ListClients(_ context.Context) ([]*storage.Client, error)

ListClients lists all registered clients

func (*Store) LogValue added in v0.2.123

func (s *Store) LogValue() slog.Value

LogValue implements slog.LogValuer so callers can emit a one-shot structured snapshot of the store's posture:

logger.Info("storage initialized", "store", store)

func (*Store) RevokeAllTokensForUserClient added in v0.1.9

func (s *Store) RevokeAllTokensForUserClient(_ context.Context, userID, clientID string) (int, error)

RevokeAllTokensForUserClient revokes all tokens (access + refresh) for a specific user+client combination. This implements the OAuth 2.1 requirement for authorization code reuse detection. Returns the number of tokens revoked and any error encountered.

func (*Store) RevokeJTI added in v0.2.120

func (s *Store) RevokeJTI(_ context.Context, jti string, expiresAt time.Time) error

RevokeJTI implements storage.RevokedTokenStore.

func (*Store) RevokeRefreshTokenFamily

func (s *Store) RevokeRefreshTokenFamily(_ context.Context, familyID string) error

RevokeRefreshTokenFamily revokes all tokens in a family (for reuse detection) This is called when token reuse is detected (OAuth 2.1 security requirement)

func (*Store) SaveAuthorizationCode

func (s *Store) SaveAuthorizationCode(ctx context.Context, code *storage.AuthorizationCode) error

SaveAuthorizationCode saves an issued authorization code

func (*Store) SaveAuthorizationState

func (s *Store) SaveAuthorizationState(_ context.Context, state *storage.AuthorizationState) error

SaveAuthorizationState saves the state of an ongoing authorization flow Stores by both client state (StateID) and provider state (ProviderState) for dual lookup

func (*Store) SaveClient

func (s *Store) SaveClient(ctx context.Context, client *storage.Client) error

SaveClient saves a registered client and tracks IP for DoS protection

func (*Store) SaveRefreshToken

func (s *Store) SaveRefreshToken(_ context.Context, refreshToken, userID string, expiresAt time.Time) error

SaveRefreshToken saves a refresh token mapping to user ID with expiry For OAuth 2.1 compliance, also tracks token family for reuse detection

func (*Store) SaveRefreshTokenWithFamily

func (s *Store) SaveRefreshTokenWithFamily(_ context.Context, refreshToken, userID, clientID, familyID string, generation int, expiresAt time.Time) error

SaveRefreshTokenWithFamily saves a refresh token with family tracking for reuse detection This is the OAuth 2.1 compliant version that enables token theft detection

func (*Store) SaveToken

func (s *Store) SaveToken(ctx context.Context, userID string, token *oauth2.Token) error

SaveToken saves an oauth2.Token for a user with optional encryption

func (*Store) SaveTokenMetadata added in v0.1.9

func (s *Store) SaveTokenMetadata(_ context.Context, tokenID string, metadata storage.TokenMetadata) error

SaveTokenMetadata saves metadata for a token. Implements storage.TokenMetadataStore. IssuedAt and ExpiresAt are set by the caller and persisted as-is.

func (*Store) SaveUserInfo

func (s *Store) SaveUserInfo(ctx context.Context, userID string, info *providers.UserInfo) error

SaveUserInfo saves user information

func (*Store) Stop

func (s *Store) Stop()

Stop gracefully stops the cleanup goroutine

func (*Store) TrackClientIP

func (s *Store) TrackClientIP(ip string)

TrackClientIP increments the client count for an IP address

func (*Store) ValidateClientSecret

func (s *Store) ValidateClientSecret(ctx context.Context, clientID, clientSecret string) error

ValidateClientSecret validates a client's secret using bcrypt Uses constant-time operations to prevent timing attacks

Jump to

Keyboard shortcuts

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