Documentation
¶
Overview ¶
Package keys provides signing key management for the OAuth authorization server. It handles key lifecycle including loading from files, generation, and retrieval.
Index ¶
Constants ¶
const DefaultAlgorithm = "ES256"
DefaultAlgorithm is the default signing algorithm for auto-generated keys. ES256 (ECDSA with P-256) is recommended by NIST and OWASP for JWT signing. It provides equivalent security to RSA-3072 with smaller keys and faster operations.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Config ¶
type Config struct {
// KeyDir is the directory containing PEM-encoded private key files.
// All key filenames are relative to this directory.
//
// In Kubernetes deployments, this is typically a mounted Secret volume:
//
// volumeMounts:
// - name: signing-keys
// mountPath: /etc/toolhive/keys
KeyDir string
// SigningKeyFile is the filename of the primary signing key (relative to KeyDir).
// This key is used for signing new tokens.
// If empty with KeyDir set, NewProviderFromConfig returns an error.
// If both KeyDir and SigningKeyFile are empty, an ephemeral key is generated.
SigningKeyFile string
// FallbackKeyFiles are filenames of additional keys for verification (relative to KeyDir).
// These keys are included in the JWKS endpoint for token verification but are NOT
// used for signing new tokens.
//
// Key rotation (single replica): update SigningKeyFile to the new key and move
// the old filename here. Tokens signed with old keys remain verifiable until
// they expire.
//
// Key rotation (multiple replicas): to avoid a window where one replica signs
// with a key not yet advertised by another replica's JWKS endpoint:
// 1. Add the new key to FallbackKeyFiles and roll out to all replicas.
// 2. Promote it to SigningKeyFile, move the old key to FallbackKeyFiles, roll out.
// 3. Remove the old key from FallbackKeyFiles after its tokens have expired.
FallbackKeyFiles []string
}
Config holds configuration for creating a KeyProvider. The caller is responsible for populating this from their own config source (environment variables, YAML files, flags, etc.).
type FileProvider ¶
type FileProvider struct {
// contains filtered or unexported fields
}
FileProvider loads signing keys from PEM files in a directory. The signing key is used for signing new tokens. All keys (signing + fallback) are exposed via PublicKeys() for JWKS. Keys are loaded once at construction time; changes require restart.
func NewFileProvider ¶
func NewFileProvider(cfg Config) (*FileProvider, error)
NewFileProvider creates a provider that loads keys from a directory. Config.SigningKeyFile is the primary key used for signing new tokens. Config.FallbackKeyFiles are loaded for JWKS verification (for key rotation). All keys are loaded immediately and validated. Supports RSA (PKCS1/PKCS8), ECDSA (SEC1/PKCS8), and Ed25519 keys.
func (*FileProvider) PublicKeys ¶
func (p *FileProvider) PublicKeys(_ context.Context) ([]*PublicKeyData, error)
PublicKeys returns public keys for all loaded keys (signing + additional). This enables verification of tokens signed with any of the loaded keys, supporting key rotation scenarios where old keys must remain valid.
func (*FileProvider) SigningKey ¶
func (p *FileProvider) SigningKey(_ context.Context) (*SigningKeyData, error)
SigningKey returns the primary signing key used for signing new tokens. Returns a copy to prevent external mutation of internal state.
type GeneratingProvider ¶
type GeneratingProvider struct {
// contains filtered or unexported fields
}
GeneratingProvider generates an ephemeral key on first access. Suitable for development but NOT recommended for production. Generated keys are lost on restart, invalidating all issued tokens.
func NewGeneratingProvider ¶
func NewGeneratingProvider(algorithm string) *GeneratingProvider
NewGeneratingProvider creates a provider that generates an ephemeral key. The key is generated lazily on first SigningKey() call. If algorithm is empty, DefaultAlgorithm (ES256) is used.
func (*GeneratingProvider) PublicKeys ¶
func (p *GeneratingProvider) PublicKeys(ctx context.Context) ([]*PublicKeyData, error)
PublicKeys returns the public key for JWKS. Generates the signing key if it hasn't been generated yet.
func (*GeneratingProvider) SigningKey ¶
func (p *GeneratingProvider) SigningKey(_ context.Context) (*SigningKeyData, error)
SigningKey returns the signing key, generating one if needed. Thread-safe: uses mutex to ensure only one key is generated. Returns a copy to prevent external mutation of internal state.
type KeyProvider ¶
type KeyProvider interface {
// SigningKey returns the current signing key.
// Returns ErrNoSigningKey if no key is available.
SigningKey(ctx context.Context) (*SigningKeyData, error)
// PublicKeys returns all public keys for the JWKS endpoint.
// May return multiple keys during rotation periods.
PublicKeys(ctx context.Context) ([]*PublicKeyData, error)
}
KeyProvider provides signing keys for JWT operations. Implementations handle key sourcing (file, memory, generation).
func NewProviderFromConfig ¶
func NewProviderFromConfig(cfg Config) (KeyProvider, error)
NewProviderFromConfig creates a KeyProvider based on the configuration.
Behavior:
- If KeyDir and SigningKeyFile are set: load keys from directory
- If both are empty: return GeneratingProvider (ephemeral key for development)
- If KeyDir is set but SigningKeyFile is empty: returns an error
type PublicKeyData ¶
type PublicKeyData struct {
// KeyID is the unique identifier for this key (RFC 7638 thumbprint).
KeyID string
// Algorithm is the signing algorithm (e.g., "ES256", "RS256").
Algorithm string
// PublicKey is the public key for verification.
PublicKey crypto.PublicKey
// CreatedAt is when this key was generated or loaded.
CreatedAt time.Time
}
PublicKeyData represents the public portion of a signing key. This is safe to expose via the JWKS endpoint.
type SigningKeyData ¶
type SigningKeyData struct {
// KeyID is the unique identifier for this key (RFC 7638 thumbprint).
KeyID string
// Algorithm is the signing algorithm (e.g., "ES256", "RS256").
Algorithm string
// Key is the private key used for signing.
Key crypto.Signer
// CreatedAt is when this key was generated or loaded.
CreatedAt time.Time
}
SigningKeyData represents a signing key with its metadata. This contains private key material and should not be exposed externally.