Documentation
¶
Index ¶
- Variables
- type AuthContextStore
- type AuthorizationContext
- type Cache
- type Logger
- type MemoryCache
- func (m *MemoryCache[V]) Delete(_ context.Context, key string)
- func (m *MemoryCache[V]) Get(_ context.Context, key string) (V, bool)
- func (m *MemoryCache[V]) GetAndDelete(_ context.Context, key string) (V, bool)
- func (m *MemoryCache[V]) Len() int
- func (m *MemoryCache[V]) Set(_ context.Context, key string, value V)
- func (m *MemoryCache[V]) SetNX(_ context.Context, key string, value V) (bool, error)
- func (m *MemoryCache[V]) SetNXWithTTL(ctx context.Context, key string, value V, ttl time.Duration) (bool, error)
- func (m *MemoryCache[V]) SetWithTTL(_ context.Context, key string, value V, ttl time.Duration)
- func (m *MemoryCache[V]) Stop()
- type MemoryStore
- func (c *MemoryStore) AddToken(ctx context.Context, code string, token *Token) error
- func (c *MemoryStore) Consent(ctx context.Context, query *AuthorizationContext) error
- func (c *MemoryStore) Create(ctx context.Context, doc *AuthorizationContext) error
- func (c *MemoryStore) Delete(ctx context.Context, id string) error
- func (c *MemoryStore) ForfeitAuthorizationCode(ctx context.Context, query *AuthorizationContext) (*AuthorizationContext, error)
- func (c *MemoryStore) Get(ctx context.Context, query *AuthorizationContext) (*AuthorizationContext, error)
- func (c *MemoryStore) GetByAccessToken(ctx context.Context, token string) (*AuthorizationContext, error)
- func (c *MemoryStore) GetByAuthorizationCode(ctx context.Context, code string) (*AuthorizationContext, error)
- func (c *MemoryStore) GetByID(ctx context.Context, id string) (*AuthorizationContext, error)
- func (c *MemoryStore) GetWithAccessToken(ctx context.Context, token string) (*AuthorizationContext, error)
- func (c *MemoryStore) MarkCodeAsForfeited(ctx context.Context, id string) error
- func (c *MemoryStore) RedeemPreAuthorizedCode(ctx context.Context, code, dpopThumbprint string) (*AuthorizationContext, error)
- func (c *MemoryStore) Save(ctx context.Context, doc *AuthorizationContext) error
- func (c *MemoryStore) SetAuthenticSource(ctx context.Context, query *AuthorizationContext, authenticSource string) error
- func (c *MemoryStore) SetIdentifier(ctx context.Context, query *AuthorizationContext, identifier string) error
- func (c *MemoryStore) Update(ctx context.Context, doc *AuthorizationContext) error
- type MongoCache
- func (m *MongoCache[V]) Delete(ctx context.Context, key string)
- func (m *MongoCache[V]) Get(ctx context.Context, key string) (V, bool)
- func (m *MongoCache[V]) GetAndDelete(ctx context.Context, key string) (V, bool)
- func (m *MongoCache[V]) Len() int
- func (m *MongoCache[V]) Set(ctx context.Context, key string, value V)
- func (m *MongoCache[V]) SetNX(ctx context.Context, key string, value V) (bool, error)
- func (m *MongoCache[V]) SetNXWithTTL(ctx context.Context, key string, value V, ttl time.Duration) (bool, error)
- func (m *MongoCache[V]) SetWithTTL(ctx context.Context, key string, value V, ttl time.Duration)
- type MongoCacheOption
- type MongoStore
- func (s *MongoStore) AddToken(ctx context.Context, code string, token *Token) error
- func (s *MongoStore) Consent(ctx context.Context, query *AuthorizationContext) error
- func (s *MongoStore) Create(ctx context.Context, doc *AuthorizationContext) error
- func (s *MongoStore) Delete(ctx context.Context, id string) error
- func (s *MongoStore) ForfeitAuthorizationCode(ctx context.Context, query *AuthorizationContext) (*AuthorizationContext, error)
- func (s *MongoStore) Get(ctx context.Context, query *AuthorizationContext) (*AuthorizationContext, error)
- func (s *MongoStore) GetByAccessToken(ctx context.Context, token string) (*AuthorizationContext, error)
- func (s *MongoStore) GetByAuthorizationCode(ctx context.Context, code string) (*AuthorizationContext, error)
- func (s *MongoStore) GetByID(ctx context.Context, id string) (*AuthorizationContext, error)
- func (s *MongoStore) GetWithAccessToken(ctx context.Context, token string) (*AuthorizationContext, error)
- func (s *MongoStore) MarkCodeAsForfeited(ctx context.Context, id string) error
- func (s *MongoStore) RedeemPreAuthorizedCode(ctx context.Context, code, dpopThumbprint string) (*AuthorizationContext, error)
- func (s *MongoStore) Save(ctx context.Context, doc *AuthorizationContext) error
- func (s *MongoStore) SetAuthenticSource(ctx context.Context, query *AuthorizationContext, authenticSource string) error
- func (s *MongoStore) SetIdentifier(ctx context.Context, query *AuthorizationContext, identifier string) error
- func (s *MongoStore) Update(ctx context.Context, doc *AuthorizationContext) error
- type Service
- type SessionStatus
- type SharedSecrets
- type Token
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ErrNoDocuments = errors.New("no documents found")
Functions ¶
This section is empty.
Types ¶
type AuthContextStore ¶
type AuthContextStore interface {
// Save stores an authorization context with sessionID as primary key.
Save(ctx context.Context, doc *AuthorizationContext) error
// Create is an alias for Save.
Create(ctx context.Context, doc *AuthorizationContext) error
// Get retrieves an authorization context by query fields (sessionID, requestURI, code, state, etc.).
Get(ctx context.Context, query *AuthorizationContext) (*AuthorizationContext, error)
// GetByID retrieves an authorization context by session ID.
GetByID(ctx context.Context, id string) (*AuthorizationContext, error)
// GetByAuthorizationCode retrieves an authorization context by authorization code.
GetByAuthorizationCode(ctx context.Context, code string) (*AuthorizationContext, error)
// GetByAccessToken retrieves an authorization context by access token.
GetByAccessToken(ctx context.Context, token string) (*AuthorizationContext, error)
// GetWithAccessToken retrieves an authorization context by access token (legacy method).
GetWithAccessToken(ctx context.Context, token string) (*AuthorizationContext, error)
// Update updates an existing authorization context.
Update(ctx context.Context, doc *AuthorizationContext) error
// Delete removes an authorization context by session ID.
Delete(ctx context.Context, id string) error
// ForfeitAuthorizationCode marks an authorization code as used and returns the updated context.
ForfeitAuthorizationCode(ctx context.Context, query *AuthorizationContext) (*AuthorizationContext, error)
// RedeemPreAuthorizedCode allows a pre-authorized code to be redeemed by multiple
// distinct clients (per DPoP thumbprint). Returns the auth context or an error if
// the same client attempts to redeem the code twice.
RedeemPreAuthorizedCode(ctx context.Context, code, dpopThumbprint string) (*AuthorizationContext, error)
// MarkCodeAsForfeited marks an authorization code as forfeited by session ID.
MarkCodeAsForfeited(ctx context.Context, id string) error
// Consent marks an authorization context as consented.
Consent(ctx context.Context, query *AuthorizationContext) error
// AddToken adds a token to an authorization context identified by code.
AddToken(ctx context.Context, code string, token *Token) error
// SetAuthenticSource sets the authentic source for an authorization context.
SetAuthenticSource(ctx context.Context, query *AuthorizationContext, authenticSource string) error
// SetIdentifier sets the resolved identifier on an authorization context.
SetIdentifier(ctx context.Context, query *AuthorizationContext, identifier string) error
}
AuthContextStore defines the interface for authorization context storage. Implementations can use in-memory caching, MongoDB, or other backends. This abstraction enables horizontal scaling (HA) by allowing shared storage backends.
type AuthorizationContext ¶
type AuthorizationContext struct {
// Core session fields
SessionID string `json:"session_id" bson:"session_id" validate:"required,max=128,printascii"`
Status SessionStatus `json:"status,omitempty" bson:"status,omitempty" validate:"omitempty,max=32,printascii"`
CreatedAt time.Time `json:"created_at" bson:"created_at,omitempty"`
ExpiresAt int64 `json:"expires_at" bson:"expires_at"`
// SourceSessionID references the parent session from which this session was
// derived. Used in the pre-authorized code flow where each client redemption
// creates a new child session that still needs access to the original
// session's credential documents.
SourceSessionID string `json:"source_session_id,omitempty" bson:"source_session_id,omitempty" validate:"omitempty,max=128,printascii"`
// Client and authorization fields
ClientID string `json:"client_id" bson:"client_id" validate:"omitempty,max=128,printascii"`
WalletClientID string `json:"wallet_client_id,omitempty" bson:"wallet_client_id,omitempty" validate:"omitempty,max=128,printascii"`
Scopes []string `json:"scopes,omitempty" bson:"scopes,omitempty"`
State string `json:"state,omitempty" bson:"state,omitempty" validate:"omitempty,max=500,printascii"`
Nonce string `json:"nonce,omitempty" bson:"nonce,omitempty" validate:"omitempty,max=128,printascii"`
CodeChallenge string `json:"code_challenge,omitempty" bson:"code_challenge,omitempty" validate:"omitempty,max=128,printascii"`
CodeChallengeMethod string `json:"code_challenge_method,omitempty" bson:"code_challenge_method,omitempty" validate:"omitempty,max=16,printascii"`
// Authorization code fields
Code string `json:"code,omitempty" bson:"code,omitempty" validate:"omitempty,max=128,printascii"`
Forfeited bool `json:"forfeited,omitempty" bson:"forfeited,omitempty"`
// RedeemedBy tracks DPoP thumbprints that have redeemed a pre-authorized code.
// Pre-authorized codes may be redeemed by multiple distinct clients (each
// identified by a unique DPoP key), but a given client must not redeem
// the same code twice.
RedeemedBy []string `json:"redeemed_by,omitempty" bson:"redeemed_by,omitempty"`
// Token fields
Token *Token `json:"token,omitempty" bson:"token,omitempty"`
AccessToken string `json:"access_token,omitempty" bson:"access_token,omitempty" validate:"omitempty,max=4096,printascii"`
IDToken string `json:"id_token,omitempty" bson:"id_token,omitempty" validate:"omitempty,max=8192,printascii"`
// Issuer-specific fields (credential issuance)
AuthorizationDetails []openid4vci.AuthorizationDetailsParameter `json:"authorization_details,omitempty" bson:"authorization_details,omitempty"`
RequestURI string `json:"request_uri,omitempty" bson:"request_uri,omitempty" validate:"omitempty,max=2048,printascii"`
WalletURI string `json:"redirect_url,omitempty" bson:"redirect_url,omitempty" validate:"omitempty,max=2048,printascii"`
Consent bool `json:"consent,omitempty" bson:"consent,omitempty"`
AuthenticSource string `json:"authentic_source,omitempty" bson:"authentic_source,omitempty" validate:"omitempty,max=128,printascii"`
Scope string `json:"scope,omitempty" bson:"scope,omitempty" validate:"omitempty,max=128,printascii"`
Identifier string `json:"identifier,omitempty" bson:"identifier,omitempty" validate:"omitempty,max=256,printascii"`
AuthProvider string `json:"auth_provider,omitempty" bson:"auth_provider,omitempty" validate:"omitempty,max=32,printascii"`
DataSource string `json:"data_source,omitempty" bson:"data_source,omitempty" validate:"omitempty,max=32,printascii"`
RemoteName string `json:"remote_name,omitempty" bson:"remote_name,omitempty" validate:"omitempty,max=128,printascii"`
// Verifier-specific fields (presentation/RP flows)
RedirectURI string `json:"redirect_uri,omitempty" bson:"redirect_uri,omitempty" validate:"omitempty,max=2048,printascii"`
ResponseType string `json:"response_type,omitempty" bson:"response_type,omitempty" validate:"omitempty,max=32,printascii"`
ResponseMode string `json:"response_mode,omitempty" bson:"response_mode,omitempty" validate:"omitempty,max=32,printascii"`
ShowCredentialDetails bool `json:"show_credential_details,omitempty" bson:"show_credential_details,omitempty"`
CodeExpiresAt int64 `json:"code_expires_at,omitempty" bson:"code_expires_at,omitempty"` // Unix timestamp
AccessTokenExpiresAt int64 `json:"access_token_expires_at,omitempty" bson:"access_token_expires_at,omitempty"` // Unix timestamp
RefreshToken string `json:"refresh_token,omitempty" bson:"refresh_token,omitempty" validate:"omitempty,max=4096,printascii"`
RefreshTokenExpiresAt int64 `json:"refresh_token_expires_at,omitempty" bson:"refresh_token_expires_at,omitempty"` // Unix timestamp
VerifiedClaims map[string]any `json:"verified_claims,omitempty" bson:"verified_claims,omitempty"`
VPToken string `json:"vp_token,omitempty" bson:"vp_token,omitempty" validate:"omitempty,max=65536,printascii"`
PresentationSubmission any `json:"presentation_submission,omitempty" bson:"presentation_submission,omitempty"`
// OpenID4VP fields (wallet interaction)
EphemeralEncryptionKeyID string `` /* 129-byte string literal not displayed */
VerifierResponseCode string `json:"verifier_response_code,omitempty" bson:"verifier_response_code,omitempty" validate:"omitempty,max=128,printascii"`
RequestObjectID string `json:"request_object_id,omitempty" bson:"request_object_id,omitempty" validate:"omitempty,max=128,printascii"`
RequestObjectNonce string `json:"request_object_nonce,omitempty" bson:"request_object_nonce,omitempty" validate:"omitempty,max=128,printascii"`
DCQLQuery *openid4vp.DCQL `json:"dcql_query,omitempty" bson:"dcql_query,omitempty"`
Validations map[string][]openid4vp.ClaimValidation `json:"validations,omitempty" bson:"validations,omitempty" validate:"omitempty,dive,dive"`
WalletID string `json:"wallet_id,omitempty" bson:"wallet_id,omitempty" validate:"omitempty,max=128,printascii"`
}
AuthorizationContext is the unified model for OIDC/OpenID4VP sessions It supports both issuer credential issuance flows and verifier presentation/RP flows
func (*AuthorizationContext) Validate ¶
func (a *AuthorizationContext) Validate() error
Validate checks the AuthorizationContext against its struct validation tags.
type Cache ¶
type Cache[V any] interface { // Get retrieves a value by key. Returns the value and true if found, // or the zero value and false if not found or expired. Get(ctx context.Context, key string) (V, bool) // Set stores a value with the default TTL configured at creation time. Set(ctx context.Context, key string, value V) // SetNX stores a value only if the key does not already exist (atomic). // Returns true if the value was set, false if the key already existed. // Returns an error on backend failures so callers can distinguish // "already exists" from operational errors. SetNX(ctx context.Context, key string, value V) (bool, error) // SetNXWithTTL stores a value only if the key does not already exist (atomic), // using a custom TTL instead of the default. Returns true if the value was set, // false if the key already existed. // If ttl <= 0, implementations MUST fall back to SetNX (default TTL). SetNXWithTTL(ctx context.Context, key string, value V, ttl time.Duration) (bool, error) // SetWithTTL stores a value with a custom TTL, overriding the default. SetWithTTL(ctx context.Context, key string, value V, ttl time.Duration) // Delete removes a value by key. Delete(ctx context.Context, key string) // GetAndDelete atomically retrieves and removes a value by key. // Returns the value and true if found, or the zero value and false if not. GetAndDelete(ctx context.Context, key string) (V, bool) // Len returns the number of items currently in the cache. Len() int }
Cache is a generic key-value cache interface with TTL support. All in-memory caches MUST use this interface to allow swapping backends for HA deployments (e.g. memory → mongo).
V is the value type. Keys are always strings, which covers all current usage across the codebase.
type Logger ¶
Logger is a minimal logging interface for operational error reporting. Both *logger.Log and logr.Logger satisfy this interface.
type MemoryCache ¶
type MemoryCache[V any] struct { // contains filtered or unexported fields }
MemoryCache is a generic in-memory cache backed by ttlcache. Suitable for single-instance deployments. For HA, swap with MongoCache.
func NewMemoryCache ¶
func NewMemoryCache[V any](ttl time.Duration) *MemoryCache[V]
NewMemoryCache creates a new in-memory generic cache with the given default TTL.
Example ¶
package main
import (
"fmt"
"time"
"github.com/SUNET/vc/pkg/cache"
)
func main() {
c := cache.NewMemoryCache[string](5 * time.Minute)
defer c.Stop()
fmt.Printf("%T\n", c)
}
Output: *cache.MemoryCache[string]
func (*MemoryCache[V]) Delete ¶
func (m *MemoryCache[V]) Delete(_ context.Context, key string)
Delete removes a value by key.
Example ¶
package main
import (
"context"
"fmt"
"time"
"github.com/SUNET/vc/pkg/cache"
)
func main() {
ctx := context.Background()
c := cache.NewMemoryCache[string](5 * time.Minute)
defer c.Stop()
c.Set(ctx, "key", "value")
fmt.Println("before delete:", c.Len())
c.Delete(ctx, "key")
_, found := c.Get(ctx, "key")
fmt.Println("after delete found:", found)
fmt.Println("after delete len:", c.Len())
}
Output: before delete: 1 after delete found: false after delete len: 0
func (*MemoryCache[V]) Get ¶
func (m *MemoryCache[V]) Get(_ context.Context, key string) (V, bool)
Get retrieves a value by key.
Example ¶
package main
import (
"context"
"fmt"
"time"
"github.com/SUNET/vc/pkg/cache"
)
func main() {
ctx := context.Background()
c := cache.NewMemoryCache[int](5 * time.Minute)
defer c.Stop()
// Get a key that does not exist
_, found := c.Get(ctx, "missing")
fmt.Println("missing key found:", found)
// Set and get a key
c.Set(ctx, "count", 42)
val, found := c.Get(ctx, "count")
fmt.Println("count found:", found)
fmt.Println("count value:", val)
}
Output: missing key found: false count found: true count value: 42
func (*MemoryCache[V]) GetAndDelete ¶ added in v0.6.1
func (m *MemoryCache[V]) GetAndDelete(_ context.Context, key string) (V, bool)
GetAndDelete atomically retrieves and removes a value by key.
func (*MemoryCache[V]) Len ¶
func (m *MemoryCache[V]) Len() int
Len returns the number of items currently in the cache.
Example ¶
package main
import (
"context"
"fmt"
"time"
"github.com/SUNET/vc/pkg/cache"
)
func main() {
ctx := context.Background()
c := cache.NewMemoryCache[string](5 * time.Minute)
defer c.Stop()
fmt.Println("empty cache len:", c.Len())
c.Set(ctx, "a", "alpha")
c.Set(ctx, "b", "bravo")
c.Set(ctx, "c", "charlie")
fmt.Println("after 3 inserts len:", c.Len())
}
Output: empty cache len: 0 after 3 inserts len: 3
func (*MemoryCache[V]) Set ¶
func (m *MemoryCache[V]) Set(_ context.Context, key string, value V)
Set stores a value with the default TTL.
Example ¶
package main
import (
"context"
"fmt"
"time"
"github.com/SUNET/vc/pkg/cache"
)
func main() {
ctx := context.Background()
c := cache.NewMemoryCache[string](5 * time.Minute)
defer c.Stop()
c.Set(ctx, "greeting", "hello")
val, found := c.Get(ctx, "greeting")
fmt.Println("found:", found)
fmt.Println("value:", val)
}
Output: found: true value: hello
func (*MemoryCache[V]) SetNX ¶ added in v0.5.10
SetNX stores a value only if the key does not already exist. Returns true if the value was set, false if the key already existed.
func (*MemoryCache[V]) SetNXWithTTL ¶ added in v0.6.4
func (m *MemoryCache[V]) SetNXWithTTL(ctx context.Context, key string, value V, ttl time.Duration) (bool, error)
SetNXWithTTL stores a value only if the key does not already exist, using a custom TTL. Returns true if the value was set, false if the key already existed. If ttl <= 0, falls back to SetNX (default TTL).
func (*MemoryCache[V]) SetWithTTL ¶
SetWithTTL stores a value with a custom TTL.
Example ¶
package main
import (
"context"
"fmt"
"time"
"github.com/SUNET/vc/pkg/cache"
)
func main() {
ctx := context.Background()
c := cache.NewMemoryCache[string](5 * time.Minute)
defer c.Stop()
// Set a value with a custom TTL
c.SetWithTTL(ctx, "session", "abc123", 30*time.Second)
val, found := c.Get(ctx, "session")
fmt.Println("found:", found)
fmt.Println("value:", val)
}
Output: found: true value: abc123
func (*MemoryCache[V]) Stop ¶
func (m *MemoryCache[V]) Stop()
Stop stops the background expiration goroutine.
type MemoryStore ¶
type MemoryStore struct {
// contains filtered or unexported fields
}
MemoryStore implements authorization context storage using an in-memory ttlcache. Suitable for single-instance deployments.
func NewMemoryStore ¶
func NewMemoryStore(ttl time.Duration) *MemoryStore
NewMemoryStore creates a new in-memory authorization context store.
func (*MemoryStore) Consent ¶
func (c *MemoryStore) Consent(ctx context.Context, query *AuthorizationContext) error
Consent marks an authorization context as consented
func (*MemoryStore) Create ¶
func (c *MemoryStore) Create(ctx context.Context, doc *AuthorizationContext) error
Create is an alias for Save to match the Session API
func (*MemoryStore) Delete ¶
func (c *MemoryStore) Delete(ctx context.Context, id string) error
Delete removes an authorization context from the cache
func (*MemoryStore) ForfeitAuthorizationCode ¶
func (c *MemoryStore) ForfeitAuthorizationCode(ctx context.Context, query *AuthorizationContext) (*AuthorizationContext, error)
ForfeitAuthorizationCode marks an authorization code as used
func (*MemoryStore) Get ¶
func (c *MemoryStore) Get(ctx context.Context, query *AuthorizationContext) (*AuthorizationContext, error)
Get retrieves an authorization context by query fields
func (*MemoryStore) GetByAccessToken ¶
func (c *MemoryStore) GetByAccessToken(ctx context.Context, token string) (*AuthorizationContext, error)
GetByAccessToken retrieves an authorization context by access token
func (*MemoryStore) GetByAuthorizationCode ¶
func (c *MemoryStore) GetByAuthorizationCode(ctx context.Context, code string) (*AuthorizationContext, error)
GetByAuthorizationCode retrieves an authorization context by authorization code
func (*MemoryStore) GetByID ¶
func (c *MemoryStore) GetByID(ctx context.Context, id string) (*AuthorizationContext, error)
GetByID retrieves an authorization context by session ID
func (*MemoryStore) GetWithAccessToken ¶
func (c *MemoryStore) GetWithAccessToken(ctx context.Context, token string) (*AuthorizationContext, error)
GetWithAccessToken retrieves an authorization context by access token
func (*MemoryStore) MarkCodeAsForfeited ¶
func (c *MemoryStore) MarkCodeAsForfeited(ctx context.Context, id string) error
MarkCodeAsForfeited marks an authorization code as forfeited
func (*MemoryStore) RedeemPreAuthorizedCode ¶ added in v0.6.1
func (c *MemoryStore) RedeemPreAuthorizedCode(ctx context.Context, code, dpopThumbprint string) (*AuthorizationContext, error)
RedeemPreAuthorizedCode allows a pre-authorized code to be redeemed by multiple distinct clients (identified by DPoP thumbprint). Each client may redeem the code only once. This implements OID4VCI §4.1.1 "single use" on a per-client basis: the code is single-use for each wallet, but the same credential offer can serve multiple wallets.
func (*MemoryStore) Save ¶
func (c *MemoryStore) Save(ctx context.Context, doc *AuthorizationContext) error
Save stores an authorization context in the cache with sessionID as primary key
func (*MemoryStore) SetAuthenticSource ¶
func (c *MemoryStore) SetAuthenticSource(ctx context.Context, query *AuthorizationContext, authenticSource string) error
SetAuthenticSource sets the authentic source for an authorization context
func (*MemoryStore) SetIdentifier ¶ added in v0.5.7
func (c *MemoryStore) SetIdentifier(ctx context.Context, query *AuthorizationContext, identifier string) error
SetIdentifier sets the resolved identifier on an authorization context.
func (*MemoryStore) Update ¶
func (c *MemoryStore) Update(ctx context.Context, doc *AuthorizationContext) error
Update updates an existing authorization context
type MongoCache ¶
type MongoCache[V any] struct { // contains filtered or unexported fields }
MongoCache is a generic cache backed by a MongoDB collection. Values are JSON-encoded before storage, which allows interface types (e.g. jwk.Key) to round-trip correctly. A TTL index on `created_at` provides automatic expiration. Enables HA by sharing state across instances.
V must be serializable by encoding/json. Interface or opaque types whose concrete type cannot be inferred by json.Unmarshal (e.g. jwk.Key) require a custom decoder supplied via WithDecoder.
func NewMongoCache ¶
func NewMongoCache[V any](ctx context.Context, client *mongo.Client, database, collection string, ttl time.Duration, log Logger, opts ...MongoCacheOption[V]) (*MongoCache[V], error)
NewMongoCache creates a new MongoDB-backed generic cache. It creates the necessary indexes including a TTL index for automatic expiration. If log is nil operational errors are silently discarded.
func (*MongoCache[V]) Delete ¶
func (m *MongoCache[V]) Delete(ctx context.Context, key string)
Delete removes a value by key.
func (*MongoCache[V]) Get ¶
func (m *MongoCache[V]) Get(ctx context.Context, key string) (V, bool)
Get retrieves a value by key.
func (*MongoCache[V]) GetAndDelete ¶ added in v0.6.1
func (m *MongoCache[V]) GetAndDelete(ctx context.Context, key string) (V, bool)
GetAndDelete atomically retrieves and removes a value by key.
func (*MongoCache[V]) Len ¶
func (m *MongoCache[V]) Len() int
Len returns the estimated number of items in the cache.
func (*MongoCache[V]) Set ¶
func (m *MongoCache[V]) Set(ctx context.Context, key string, value V)
Set stores a value with the default TTL (uses upsert).
func (*MongoCache[V]) SetNX ¶ added in v0.5.10
SetNX stores a value only if the key does not already exist (atomic). Returns true if the value was inserted, false if the key already existed. Returns a non-nil error on operational failures (e.g. connectivity issues).
func (*MongoCache[V]) SetNXWithTTL ¶ added in v0.6.4
func (m *MongoCache[V]) SetNXWithTTL(ctx context.Context, key string, value V, ttl time.Duration) (bool, error)
SetNXWithTTL stores a value only if the key does not already exist (atomic), using a custom TTL approximated via created_at shifting (same as SetWithTTL). If ttl <= 0, falls back to SetNX (default TTL).
func (*MongoCache[V]) SetWithTTL ¶
SetWithTTL stores a value with a custom TTL. MongoDB TTL indexes are collection-wide, so per-entry TTL is approximated by shifting created_at: the document expires when
now >= created_at + collection_ttl
Setting created_at = now - (collection_ttl - custom_ttl) makes the document expire ~custom_ttl from now.
type MongoCacheOption ¶ added in v0.5.10
type MongoCacheOption[V any] func(*MongoCache[V])
MongoCacheOption configures optional behaviour for MongoCache.
func WithDecoder ¶ added in v0.5.10
func WithDecoder[V any](fn func([]byte) (V, error)) MongoCacheOption[V]
WithDecoder supplies a custom JSON decoder for V. Use this for interface types (e.g. jwk.Key) where json.Unmarshal cannot infer the concrete type.
type MongoStore ¶
type MongoStore struct {
// contains filtered or unexported fields
}
MongoStore implements AuthContextStore using MongoDB as the backend. This enables horizontal scaling (HA) by sharing session state across instances.
func NewMongoStore ¶
func NewMongoStore(ctx context.Context, client *mongo.Client, database, collection string, ttl time.Duration) (*MongoStore, error)
NewMongoStore creates a new MongoDB-backed authorization context store. It sets up the collection with required indexes including a TTL index for automatic expiration.
func (*MongoStore) Consent ¶
func (s *MongoStore) Consent(ctx context.Context, query *AuthorizationContext) error
Consent marks an authorization context as consented.
func (*MongoStore) Create ¶
func (s *MongoStore) Create(ctx context.Context, doc *AuthorizationContext) error
Create is an alias for Save.
func (*MongoStore) Delete ¶
func (s *MongoStore) Delete(ctx context.Context, id string) error
Delete removes an authorization context by session ID.
func (*MongoStore) ForfeitAuthorizationCode ¶
func (s *MongoStore) ForfeitAuthorizationCode(ctx context.Context, query *AuthorizationContext) (*AuthorizationContext, error)
ForfeitAuthorizationCode marks an authorization code as used.
func (*MongoStore) Get ¶
func (s *MongoStore) Get(ctx context.Context, query *AuthorizationContext) (*AuthorizationContext, error)
Get retrieves an authorization context by query fields.
func (*MongoStore) GetByAccessToken ¶
func (s *MongoStore) GetByAccessToken(ctx context.Context, token string) (*AuthorizationContext, error)
GetByAccessToken retrieves an authorization context by access token.
func (*MongoStore) GetByAuthorizationCode ¶
func (s *MongoStore) GetByAuthorizationCode(ctx context.Context, code string) (*AuthorizationContext, error)
GetByAuthorizationCode retrieves an authorization context by authorization code.
func (*MongoStore) GetByID ¶
func (s *MongoStore) GetByID(ctx context.Context, id string) (*AuthorizationContext, error)
GetByID retrieves an authorization context by session ID.
func (*MongoStore) GetWithAccessToken ¶
func (s *MongoStore) GetWithAccessToken(ctx context.Context, token string) (*AuthorizationContext, error)
GetWithAccessToken retrieves an authorization context by access token (legacy method).
func (*MongoStore) MarkCodeAsForfeited ¶
func (s *MongoStore) MarkCodeAsForfeited(ctx context.Context, id string) error
MarkCodeAsForfeited marks an authorization code as forfeited by session ID.
func (*MongoStore) RedeemPreAuthorizedCode ¶ added in v0.6.1
func (s *MongoStore) RedeemPreAuthorizedCode(ctx context.Context, code, dpopThumbprint string) (*AuthorizationContext, error)
RedeemPreAuthorizedCode allows a pre-authorized code to be redeemed by multiple distinct clients (identified by DPoP thumbprint). Uses an atomic FindOneAndUpdate with $addToSet and a condition that the thumbprint is not already present. The $expr size guard is enforced atomically within the single-document FindOneAndUpdate operation, so the max-redeemer bound is strict.
func (*MongoStore) Save ¶
func (s *MongoStore) Save(ctx context.Context, doc *AuthorizationContext) error
Save stores an authorization context in MongoDB with sessionID as primary key.
func (*MongoStore) SetAuthenticSource ¶
func (s *MongoStore) SetAuthenticSource(ctx context.Context, query *AuthorizationContext, authenticSource string) error
SetAuthenticSource sets the authentic source for an authorization context.
func (*MongoStore) SetIdentifier ¶ added in v0.5.7
func (s *MongoStore) SetIdentifier(ctx context.Context, query *AuthorizationContext, identifier string) error
SetIdentifier sets the resolved identifier on an authorization context.
func (*MongoStore) Update ¶
func (s *MongoStore) Update(ctx context.Context, doc *AuthorizationContext) error
Update updates an existing authorization context.
type Service ¶
type Service struct {
// contains filtered or unexported fields
}
Service manages cache creation. When HA is enabled, caches are backed by MongoDB using the provided client; otherwise in-memory.
func New ¶
New creates a cache Service. When ha is true the supplied mongo client is used for all caches; otherwise every cache is in-memory. The caller owns the client lifecycle. databaseName is the MongoDB database name to use for all caches. If log is nil operational errors from mongo-backed caches are silently discarded.
func (*Service) NewAuthContextCache ¶
func (s *Service) NewAuthContextCache(ctx context.Context, collection string, ttl time.Duration) (AuthContextStore, error)
NewAuthContextCache creates an AuthContextStore backed by the service's backend.
type SessionStatus ¶
type SessionStatus string
SessionStatus represents the status of an OIDC session
const ( SessionStatusPending SessionStatus = "pending" SessionStatusAwaitingPresentation SessionStatus = "awaiting_presentation" SessionStatusCodeIssued SessionStatus = "code_issued" SessionStatusTokenIssued SessionStatus = "token_issued" SessionStatusCompleted SessionStatus = "completed" SessionStatusExpired SessionStatus = "expired" SessionStatusError SessionStatus = "error" // MaxPreAuthRedeemers is the maximum number of distinct clients that can // redeem a single pre-authorized code. This prevents unbounded growth of // the RedeemedBy array and child sessions if a code leaks. MaxPreAuthRedeemers = 10 )
type SharedSecrets ¶
type SharedSecrets struct {
ServiceName string `bson:"_id"`
SessionAuthKey string `bson:"session_auth_key"`
SessionEncKey string `bson:"session_enc_key"`
}
SharedSecrets holds session keys that must be identical across all instances of a service in HA mode.
func EnsureSharedSecrets ¶
func EnsureSharedSecrets(ctx context.Context, s *Service, serviceName string) (*SharedSecrets, error)
EnsureSharedSecrets returns session keys that are guaranteed to be identical across every instance that calls this function with the same serviceName.
When the Service is in HA mode it generates candidate keys and atomically inserts them into MongoDB using FindOneAndUpdate with $setOnInsert + upsert. If another instance races and inserts first, MongoDB returns that existing document instead — no conflicts.
When HA is disabled it simply generates ephemeral keys.
type Token ¶
type Token struct {
AccessToken string `json:"access_token" bson:"access_token" validate:"required,max=4096,printascii"`
ExpiresAt int64 `json:"expires_at" bson:"expires_at" validate:"required"`
DPoPThumbprint string `json:"dpop_thumbprint,omitempty" bson:"dpop_thumbprint,omitempty" validate:"omitempty,max=128,printascii"`
}
Token represents an access token with expiration