keys

package
v0.1.11 Latest Latest
Warning

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

Go to latest
Published: May 30, 2026 License: Apache-2.0 Imports: 17 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 AddKidRequest added in v0.1.7

type AddKidRequest struct {
	Kid       string
	Key       any
	Algorithm string
	ClientID  string
	ExpiresAt time.Time
}

AddKidRequest is the input to KidStorage.Add. If ExpiresAt is zero, the kid has no expiry (current key).

type AddKidResponse added in v0.1.7

type AddKidResponse struct{}

AddKidResponse is the output of KidStorage.Add.

type CleanExpiredRequest added in v0.1.7

type CleanExpiredRequest struct{}

CleanExpiredRequest is the input to KidStorage.CleanExpired.

type CleanExpiredResponse added in v0.1.7

type CleanExpiredResponse struct {
	// Removed is the number of expired records evicted by this call.
	Removed int
}

CleanExpiredResponse is the output of KidStorage.CleanExpired.

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

GetKey tries each lookup in order for a client_id match.

func (*CompositeKeyLookup) GetKeyByKid

GetKeyByKid tries each lookup in order for a kid match.

type DeleteKeyRequest added in v0.1.7

type DeleteKeyRequest struct {
	ClientID string
}

DeleteKeyRequest is the input to KeyStorage.DeleteKey.

type DeleteKeyResponse added in v0.1.7

type DeleteKeyResponse struct{}

DeleteKeyResponse is the output of KeyStorage.DeleteKey.

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

DeleteKey delegates to the inner store.

func (*EncryptedKeyStorage) GetKey

GetKey retrieves and decrypts the key for the given clientID.

func (*EncryptedKeyStorage) GetKeyByKid

GetKeyByKid retrieves and decrypts the key matching the given kid.

func (*EncryptedKeyStorage) ListKeyIDs

ListKeyIDs delegates to the inner store.

func (*EncryptedKeyStorage) PutKey

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

type GetKeyByKidRequest added in v0.1.7

type GetKeyByKidRequest struct {
	Kid string
}

GetKeyByKidRequest is the input to KeyLookup.GetKeyByKid.

type GetKeyByKidResponse added in v0.1.7

type GetKeyByKidResponse struct {
	Record *KeyRecord
}

GetKeyByKidResponse is the output of KeyLookup.GetKeyByKid.

type GetKeyRequest added in v0.1.7

type GetKeyRequest struct {
	ClientID string
}

GetKeyRequest is the input to KeyLookup.GetKey.

type GetKeyResponse added in v0.1.7

type GetKeyResponse struct {
	Record *KeyRecord
}

GetKeyResponse is the output of KeyLookup.GetKey.

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

DeleteKey removes the key for the given clientID.

func (*InMemoryKeyStore) GetKey

GetKey returns the key record for the given clientID.

func (*InMemoryKeyStore) GetKeyByKid

GetKeyByKid returns the key record matching the given kid.

func (*InMemoryKeyStore) ListKeyIDs

ListKeyIDs returns all registered client IDs.

func (*InMemoryKeyStore) PutKey

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

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 KeyLookup (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) GetKey

func (s *JWKSKeyStore) GetKey(ctx context.Context, req *GetKeyRequest) (*GetKeyResponse, error)

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

func (*JWKSKeyStore) GetKeyByKid

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) 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(ctx context.Context, req *GetKeyRequest) (*GetKeyResponse, error)

	// GetKeyByKid returns the key record matching the given kid.
	// Returns ErrKidNotFound if no key matches or the key has expired.
	GetKeyByKid(ctx context.Context, req *GetKeyByKidRequest) (*GetKeyByKidResponse, 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 req.Record.Kid is empty, it is
	// auto-computed from the key material and algorithm. Overwrites any
	// existing key for the same ClientID.
	PutKey(ctx context.Context, req *PutKeyRequest) (*PutKeyResponse, error)

	// DeleteKey removes the key for the given clientID.
	DeleteKey(ctx context.Context, req *DeleteKeyRequest) (*DeleteKeyResponse, error)

	// ListKeyIDs returns all registered client IDs.
	ListKeyIDs(ctx context.Context, req *ListKeyIDsRequest) (*ListKeyIDsResponse, error)
}

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

type KidStorage added in v0.0.83

type KidStorage interface {
	KeyLookup

	// Add registers a kid→key mapping. If req.ExpiresAt is zero, the key
	// has no expiry. Re-adding an existing kid overwrites it.
	Add(ctx context.Context, req *AddKidRequest) (*AddKidResponse, error)

	// Remove deletes a kid entry. Removing an absent kid is not an error.
	Remove(ctx context.Context, req *RemoveKidRequest) (*RemoveKidResponse, error)

	// CleanExpired removes all entries whose expiry has passed.
	CleanExpired(ctx context.Context, req *CleanExpiredRequest) (*CleanExpiredResponse, error)
}

KidStorage is the write side of a kid-indexed key store. It extends the read-only KeyLookup with the grace-period operations KidStore provides, so retired keys can be persisted across process restarts by backends in stores/ (FS, GORM, GAE) rather than living only in process memory.

Unlike KeyStorage, KidStorage is keyed by kid (not clientID): GetKey by clientID always returns ErrKeyNotFound — only GetKeyByKid is meaningful.

type KidStore

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

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

Usage during rotation:

  1. kidStore.Add(ctx, &AddKidRequest{Kid: oldKid, Key: oldKey, Algorithm: alg, ClientID: clientID, ExpiresAt: time.Now().Add(gracePeriod)})
  2. keyStorage.PutKey(ctx, &PutKeyRequest{Record: 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(ctx context.Context, req *AddKidRequest) (*AddKidResponse, error)

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

func (*KidStore) CleanExpired

func (s *KidStore) CleanExpired(ctx context.Context, req *CleanExpiredRequest) (*CleanExpiredResponse, error)

CleanExpired removes all expired entries.

func (*KidStore) GetKey

func (s *KidStore) GetKey(ctx context.Context, req *GetKeyRequest) (*GetKeyResponse, error)

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

func (*KidStore) GetKeyByKid

func (s *KidStore) GetKeyByKid(ctx context.Context, req *GetKeyByKidRequest) (*GetKeyByKidResponse, 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

Remove deletes a kid entry. Removing an absent kid is not an error.

type ListKeyIDsRequest added in v0.1.7

type ListKeyIDsRequest struct{}

ListKeyIDsRequest is the input to KeyStorage.ListKeyIDs.

type ListKeyIDsResponse added in v0.1.7

type ListKeyIDsResponse struct {
	ClientIDs []string
}

ListKeyIDsResponse is the output of KeyStorage.ListKeyIDs.

type PutKeyRequest added in v0.1.7

type PutKeyRequest struct {
	Record *KeyRecord
}

PutKeyRequest is the input to KeyStorage.PutKey.

type PutKeyResponse added in v0.1.7

type PutKeyResponse struct{}

PutKeyResponse is the output of KeyStorage.PutKey.

type RemoveKidRequest added in v0.1.7

type RemoveKidRequest struct {
	Kid string
}

RemoveKidRequest is the input to KidStorage.Remove.

type RemoveKidResponse added in v0.1.7

type RemoveKidResponse struct{}

RemoveKidResponse is the output of KidStorage.Remove.

Jump to

Keyboard shortcuts

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