Class: Keycardai::OAuth::JWKSKeyring
- Inherits:
-
Object
- Object
- Keycardai::OAuth::JWKSKeyring
- Defined in:
- lib/keycardai/oauth/jwks_keyring.rb
Overview
Resolves and caches JWKS verification keys for an issuer (RFC 7517), so bearer-token verification on a hot path does not hit the network per request. Resolution is a lookup keyed by (issuer, kid): discover the issuer's jwks_uri (RFC 8414), fetch the key set, select the key matching the kid. Both steps are cached with a TTL; the key cache is bounded and evicts its oldest entry on overflow.
The cache is in-memory and local to this instance. Thread-safe: concurrent resolutions for the same issuer are de-duplicated so a burst of cold-cache requests triggers a single discovery and a single JWKS fetch.
Constant Summary collapse
- DEFAULT_KEY_TTL =
300- DEFAULT_DISCOVERY_TTL =
3600- DEFAULT_FETCH_TIMEOUT =
10- MAX_CACHED_KEYS =
256
Instance Method Summary collapse
-
#initialize(http_client: HTTP::NetHTTPClient.new, key_ttl: DEFAULT_KEY_TTL, discovery_ttl: DEFAULT_DISCOVERY_TTL, fetch_timeout: DEFAULT_FETCH_TIMEOUT, clock: -> { Time.now }) ⇒ JWKSKeyring
constructor
A new instance of JWKSKeyring.
-
#invalidate(issuer = nil) ⇒ void
Drop cached keys and discovery results, for one issuer or all.
-
#key(issuer, kid) ⇒ OpenSSL::PKey::PKey
Resolve the verification key for a token's issuer and kid.
Constructor Details
#initialize(http_client: HTTP::NetHTTPClient.new, key_ttl: DEFAULT_KEY_TTL, discovery_ttl: DEFAULT_DISCOVERY_TTL, fetch_timeout: DEFAULT_FETCH_TIMEOUT, clock: -> { Time.now }) ⇒ JWKSKeyring
Returns a new instance of JWKSKeyring.
31 32 33 34 35 36 37 38 39 40 41 42 43 |
# File 'lib/keycardai/oauth/jwks_keyring.rb', line 31 def initialize(http_client: HTTP::NetHTTPClient.new, key_ttl: DEFAULT_KEY_TTL, discovery_ttl: DEFAULT_DISCOVERY_TTL, fetch_timeout: DEFAULT_FETCH_TIMEOUT, clock: -> { Time.now }) @http_client = http_client @key_ttl = key_ttl @discovery_ttl = discovery_ttl @fetch_timeout = fetch_timeout @clock = clock @keys = {} @discovery = {} @issuer_locks = {} @mutex = Mutex.new end |
Instance Method Details
#invalidate(issuer = nil) ⇒ void
This method returns an undefined value.
Drop cached keys and discovery results, for one issuer or all.
68 69 70 71 72 73 74 75 76 77 78 |
# File 'lib/keycardai/oauth/jwks_keyring.rb', line 68 def invalidate(issuer = nil) @mutex.synchronize do if issuer @keys.delete_if { |(cached_issuer, _), _| cached_issuer == issuer } @discovery.delete(issuer) else @keys.clear @discovery.clear end end end |
#key(issuer, kid) ⇒ OpenSSL::PKey::PKey
Resolve the verification key for a token's issuer and kid.
54 55 56 57 58 59 60 61 62 |
# File 'lib/keycardai/oauth/jwks_keyring.rb', line 54 def key(issuer, kid) cached = @mutex.synchronize { fresh_key(issuer, kid) } return cached if cached issuer_lock(issuer).synchronize do cached = @mutex.synchronize { fresh_key(issuer, kid) } cached || resolve(issuer, kid) end end |