keys

package
v0.0.75 Latest Latest
Warning

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

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

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrKeyNotFound       = fmt.Errorf("signing key not found")
	ErrAlgorithmMismatch = fmt.Errorf("algorithm mismatch")
	ErrKidNotFound       = fmt.Errorf("key not found for kid")
)

Common errors for key operations

Functions

This section is empty.

Types

type CompositeKeyLookup

type CompositeKeyLookup struct {
	Lookups []KeyLookup
}

CompositeKeyLookup tries multiple KeyLookups in order, returning the first successful result. Used to combine a KeyStorage's current-key lookup with a KidStore's grace-period entries.

func (*CompositeKeyLookup) GetKey

func (c *CompositeKeyLookup) GetKey(clientID string) (*KeyRecord, error)

GetKey tries each lookup in order for a client_id match.

func (*CompositeKeyLookup) GetKeyByKid

func (c *CompositeKeyLookup) GetKeyByKid(kid string) (*KeyRecord, error)

GetKeyByKid tries each lookup in order for a kid match.

type EncryptedKeyStorage

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

EncryptedKeyStorage is a KeyStorage decorator that transparently encrypts HMAC (HS256/HS384/HS512) client secrets at rest using AES-256-GCM. Asymmetric keys (RS256, ES256 public keys) pass through unencrypted.

Because it wraps KeyStorage and operates on KeyRecord, it only needs to implement 5 methods — no manual forwarding of individual field accessors.

The kid is computed from plaintext key material in PutKey before encryption, so kid-based lookups work correctly even though the stored bytes are encrypted.

func NewEncryptedKeyStorage

func NewEncryptedKeyStorage(inner KeyStorage, masterKeyHex string) (*EncryptedKeyStorage, error)

NewEncryptedKeyStorage creates an EncryptedKeyStorage wrapping inner. masterKeyHex must be exactly 64 hex characters (32 bytes).

func (*EncryptedKeyStorage) DeleteKey

func (e *EncryptedKeyStorage) DeleteKey(clientID string) error

DeleteKey delegates to the inner store.

func (*EncryptedKeyStorage) GetCurrentKid

func (e *EncryptedKeyStorage) GetCurrentKid(clientID string) (string, error)

GetCurrentKid returns the kid for the given clientID.

func (*EncryptedKeyStorage) GetExpectedAlg

func (e *EncryptedKeyStorage) GetExpectedAlg(clientID string) (string, error)

GetExpectedAlg is a convenience method for callers using the old interface.

func (*EncryptedKeyStorage) GetKey

func (e *EncryptedKeyStorage) GetKey(clientID string) (*KeyRecord, error)

GetKey retrieves and decrypts the key for the given clientID.

func (*EncryptedKeyStorage) GetKeyByKid

func (e *EncryptedKeyStorage) GetKeyByKid(kid string) (*KeyRecord, error)

GetKeyByKid retrieves and decrypts the key matching the given kid.

func (*EncryptedKeyStorage) GetSigningKey

func (e *EncryptedKeyStorage) GetSigningKey(clientID string) (any, error)

GetSigningKey is a convenience method for callers using the old interface.

func (*EncryptedKeyStorage) GetVerifyKey

func (e *EncryptedKeyStorage) GetVerifyKey(clientID string) (any, error)

GetVerifyKey is a convenience method for callers using the old interface.

func (*EncryptedKeyStorage) ListKeyIDs

func (e *EncryptedKeyStorage) ListKeyIDs() ([]string, error)

ListKeyIDs delegates to the inner store.

func (*EncryptedKeyStorage) ListKeys

func (e *EncryptedKeyStorage) ListKeys() ([]string, error)

ListKeys is a convenience alias for ListKeyIDs.

func (*EncryptedKeyStorage) PutKey

func (e *EncryptedKeyStorage) PutKey(rec *KeyRecord) error

PutKey computes kid from plaintext, then encrypts HMAC keys before storing.

func (*EncryptedKeyStorage) RegisterKey

func (e *EncryptedKeyStorage) RegisterKey(clientID string, key any, algorithm string) error

RegisterKey is a convenience method for callers using the old interface.

type InMemoryKeyStore

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

InMemoryKeyStore is a thread-safe in-memory KeyStorage implementation. Suitable for testing and simple single-process deployments.

func NewInMemoryKeyStore

func NewInMemoryKeyStore() *InMemoryKeyStore

NewInMemoryKeyStore creates a new empty InMemoryKeyStore.

func (*InMemoryKeyStore) DeleteKey

func (s *InMemoryKeyStore) DeleteKey(clientID string) error

DeleteKey removes the key for the given clientID.

func (*InMemoryKeyStore) GetCurrentKid

func (s *InMemoryKeyStore) GetCurrentKid(clientID string) (string, error)

GetCurrentKid returns the kid for the given clientID.

func (*InMemoryKeyStore) GetExpectedAlg

func (s *InMemoryKeyStore) GetExpectedAlg(clientID string) (string, error)

GetExpectedAlg is a convenience method matching the old KeyStore interface.

func (*InMemoryKeyStore) GetKey

func (s *InMemoryKeyStore) GetKey(clientID string) (*KeyRecord, error)

GetKey returns the key record for the given clientID.

func (*InMemoryKeyStore) GetKeyByKid

func (s *InMemoryKeyStore) GetKeyByKid(kid string) (*KeyRecord, error)

GetKeyByKid returns the key record matching the given kid.

func (*InMemoryKeyStore) GetSigningKey

func (s *InMemoryKeyStore) GetSigningKey(clientID string) (any, error)

GetSigningKey is a convenience method matching the old KeyStore interface.

func (*InMemoryKeyStore) GetVerifyKey

func (s *InMemoryKeyStore) GetVerifyKey(clientID string) (any, error)

GetVerifyKey is a convenience method matching the old KeyStore interface.

func (*InMemoryKeyStore) ListKeyIDs

func (s *InMemoryKeyStore) ListKeyIDs() ([]string, error)

ListKeyIDs returns all registered client IDs.

func (*InMemoryKeyStore) ListKeys

func (s *InMemoryKeyStore) ListKeys() ([]string, error)

ListKeys is a convenience alias for ListKeyIDs.

func (*InMemoryKeyStore) PutKey

func (s *InMemoryKeyStore) PutKey(rec *KeyRecord) error

PutKey stores a key record. Computes Kid from key material if not set.

func (*InMemoryKeyStore) RegisterKey

func (s *InMemoryKeyStore) RegisterKey(clientID string, key any, algorithm string) error

RegisterKey is a convenience method matching the old WritableKeyStore interface.

type JWKSHandler

type JWKSHandler struct {
	KeyStore    KeyStorage // needs ListKeyIDs() and GetKey()
	KidStore    *KidStore  // optional: serves previous keys during grace period
	CacheMaxAge int        // Cache-Control max-age in seconds (default: 3600)
}

JWKSHandler serves a JWKS (JSON Web Key Set) endpoint at /.well-known/jwks.json. Only asymmetric keys (RS256/ES256) are included — HS256 secrets are never exposed.

func (*JWKSHandler) ServeHTTP

func (h *JWKSHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)

type JWKSKeyStore

type JWKSKeyStore struct {
	JWKSURL         string
	HTTPClient      *http.Client
	RefreshInterval time.Duration // default: 1 hour
	MinRefreshGap   time.Duration // default: 5 seconds
	// contains filtered or unexported fields
}

JWKSKeyStore implements KeyStore (read-only) by fetching public keys from a remote JWKS endpoint. It caches keys locally and refreshes them periodically.

func NewJWKSKeyStore

func NewJWKSKeyStore(jwksURL string, opts ...JWKSOption) *JWKSKeyStore

NewJWKSKeyStore creates a new JWKSKeyStore. Call Start() to begin fetching keys.

func (*JWKSKeyStore) GetExpectedAlg

func (s *JWKSKeyStore) GetExpectedAlg(clientID string) (string, error)

GetExpectedAlg returns the algorithm for the given client ID.

func (*JWKSKeyStore) GetKey

func (s *JWKSKeyStore) GetKey(clientID string) (*KeyRecord, error)

GetKey returns ErrKeyNotFound — JWKSKeyStore only supports kid-based lookup. JWKS doesn't carry clientID→key mappings; use GetKeyByKid instead.

func (*JWKSKeyStore) GetKeyByKid

func (s *JWKSKeyStore) GetKeyByKid(kid string) (*KeyRecord, error)

GetKeyByKid returns the key record for the given kid. ClientID is empty since JWKS doesn't carry client_id metadata — the middleware skips the cross-app check in this case.

func (*JWKSKeyStore) GetSigningKey

func (s *JWKSKeyStore) GetSigningKey(clientID string) (any, error)

GetSigningKey always returns an error — JWKS only exposes public keys.

func (*JWKSKeyStore) GetVerifyKey

func (s *JWKSKeyStore) GetVerifyKey(clientID string) (any, error)

GetVerifyKey returns the public key for the given client ID. If the key is not cached, triggers a refresh before returning ErrKeyNotFound.

func (*JWKSKeyStore) Start

func (s *JWKSKeyStore) Start() error

Start performs the initial JWKS fetch and starts background refresh.

func (*JWKSKeyStore) Stop

func (s *JWKSKeyStore) Stop()

Stop stops the background refresh goroutine.

type JWKSOption

type JWKSOption func(*JWKSKeyStore)

JWKSOption configures a JWKSKeyStore.

func WithHTTPClient

func WithHTTPClient(c *http.Client) JWKSOption

WithHTTPClient sets the HTTP client for JWKS fetching.

func WithMinRefreshGap

func WithMinRefreshGap(d time.Duration) JWKSOption

WithMinRefreshGap sets the minimum time between refreshes (prevents stampede).

func WithRefreshInterval

func WithRefreshInterval(d time.Duration) JWKSOption

WithRefreshInterval sets how often keys are refreshed in the background.

type KeyLookup

type KeyLookup interface {
	// GetKey returns the key record for the given clientID.
	// Returns ErrKeyNotFound if the client has no registered key.
	GetKey(clientID string) (*KeyRecord, error)

	// GetKeyByKid returns the key record matching the given kid.
	// Returns ErrKidNotFound if no key matches or the key has expired.
	GetKeyByKid(kid string) (*KeyRecord, error)
}

KeyLookup provides read-only key lookup by clientID or kid. Implemented by all keystores, including read-only ones like JWKSKeyStore.

type KeyRecord

type KeyRecord struct {
	ClientID  string // owning client/app
	Key       any    // []byte for HMAC, PEM bytes for asymmetric
	Algorithm string // "HS256", "RS256", "ES256", etc.
	Kid       string // key identifier, computed from key material
}

KeyRecord holds all fields for a stored signing key. All key operations work with this type rather than separate accessor methods.

type KeyStorage

type KeyStorage interface {
	KeyLookup

	// PutKey stores a key record. If Kid is empty, it is auto-computed
	// from the key material and algorithm. Overwrites any existing key
	// for the same ClientID.
	PutKey(record *KeyRecord) error

	// DeleteKey removes the key for the given clientID.
	DeleteKey(clientID string) error

	// ListKeyIDs returns all registered client IDs.
	ListKeyIDs() ([]string, error)
}

KeyStorage extends KeyLookup with write operations. Implemented by persistent backends (InMemory, GORM, FS, GAE).

type KidStore

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

KidStore is an in-memory KeyLookup that tracks kid→key mappings, including grace-period entries retained during key rotation.

Usage during rotation:

  1. kidStore.Add(oldKid, oldKey, alg, clientID, time.Now().Add(gracePeriod))
  2. keyStorage.PutKey(newRecord) // overwrites current
  3. kidStore holds the old key until grace period expires

func NewKidStore

func NewKidStore() *KidStore

NewKidStore creates a new empty KidStore.

func (*KidStore) Add

func (s *KidStore) Add(kid string, key any, algorithm string, clientID string, expiresAt time.Time)

Add registers a kid→key mapping. If expiresAt is zero, the key has no expiry.

func (*KidStore) CleanExpired

func (s *KidStore) CleanExpired()

CleanExpired removes all expired entries.

func (*KidStore) GetKey

func (s *KidStore) GetKey(clientID string) (*KeyRecord, error)

GetKey always returns ErrKeyNotFound — KidStore only supports kid-based lookup.

func (*KidStore) GetKeyByKid

func (s *KidStore) GetKeyByKid(kid string) (*KeyRecord, error)

GetKeyByKid returns the key record for the given kid. Returns ErrKidNotFound if the kid is unknown or expired.

func (*KidStore) Len

func (s *KidStore) Len() int

Len returns the number of entries (including expired ones not yet cleaned).

func (*KidStore) Remove

func (s *KidStore) Remove(kid string)

Remove deletes a kid entry.

Jump to

Keyboard shortcuts

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