Class: Keycardai::OAuth::TokenVerifier

Inherits:
Object
  • Object
show all
Defined in:
lib/keycardai/oauth/token_verifier.rb

Overview

Server-tier bearer-token verification: JWTVerifier over a JWKSKeyring, returning an AccessToken. Construct once per server with the trusted zone issuer(s); JWKS and discovery caches are keyed by issuer so no zone's keys are ever served for another.

Instance Method Summary collapse

Constructor Details

#initialize(issuers:, audiences: nil, http_client: HTTP::NetHTTPClient.new, key_ttl: JWKSKeyring::DEFAULT_KEY_TTL, discovery_ttl: JWKSKeyring::DEFAULT_DISCOVERY_TTL, fetch_timeout: JWKSKeyring::DEFAULT_FETCH_TIMEOUT, clock: -> { Time.now }) ⇒ TokenVerifier

Returns a new instance of TokenVerifier.

Parameters:

  • issuers (String, Array<String>)

    trusted zone issuer URL(s)

  • audiences (String, Array<String>, nil) (defaults to: nil)

    when set, tokens must carry an intersecting aud

  • http_client (#get) (defaults to: HTTP::NetHTTPClient.new)

    pluggable transport

  • key_ttl (Numeric) (defaults to: JWKSKeyring::DEFAULT_KEY_TTL)

    JWKS key cache lifetime in seconds

  • discovery_ttl (Numeric) (defaults to: JWKSKeyring::DEFAULT_DISCOVERY_TTL)

    jwks_uri cache lifetime in seconds

  • fetch_timeout (Numeric) (defaults to: JWKSKeyring::DEFAULT_FETCH_TIMEOUT)

    discovery and JWKS fetch timeout

  • clock (#call) (defaults to: -> { Time.now })

    returns the current Time; override in tests

Raises:



87
88
89
90
91
92
93
94
95
96
97
# File 'lib/keycardai/oauth/token_verifier.rb', line 87

def initialize(issuers:, audiences: nil, http_client: HTTP::NetHTTPClient.new,
               key_ttl: JWKSKeyring::DEFAULT_KEY_TTL, discovery_ttl: JWKSKeyring::DEFAULT_DISCOVERY_TTL,
               fetch_timeout: JWKSKeyring::DEFAULT_FETCH_TIMEOUT, clock: -> { Time.now })
  @issuers = Array(issuers).reject { |issuer| issuer.nil? || issuer.empty? }
  raise ConfigurationError, "TokenVerifier requires at least one trusted issuer" if @issuers.empty?

  @audiences = audiences
  @clock = clock
  @keyring = JWKSKeyring.new(http_client: http_client, key_ttl: key_ttl,
                             discovery_ttl: discovery_ttl, fetch_timeout: fetch_timeout, clock: clock)
end

Instance Method Details

#clear_cachevoid

This method returns an undefined value.

Drop all cached keys and discovery results.



125
126
127
# File 'lib/keycardai/oauth/token_verifier.rb', line 125

def clear_cache
  @keyring.invalidate
end

#verify_token(token) ⇒ AccessToken

Verify a bearer token against the configured issuer allowlist.

Parameters:

  • token (String)

Returns:

Raises:



104
105
106
# File 'lib/keycardai/oauth/token_verifier.rb', line 104

def verify_token(token)
  verify_against(@issuers, token)
end

#verify_token_for_zone(token, issuer) ⇒ AccessToken

Verify a bearer token pinned to one zone's issuer. A token minted by any other zone is rejected before key resolution, and an issuer outside the configured allowlist fails closed.

Parameters:

  • token (String)
  • issuer (String)

    the zone's issuer URL

Returns:

Raises:



116
117
118
119
120
# File 'lib/keycardai/oauth/token_verifier.rb', line 116

def verify_token_for_zone(token, issuer)
  raise InvalidTokenError, "zone issuer is not configured on this verifier" unless @issuers.include?(issuer)

  verify_against([issuer], token)
end