Class: Keycardai::OAuth::WebIdentity
- Inherits:
-
Object
- Object
- Keycardai::OAuth::WebIdentity
- Defined in:
- lib/keycardai/oauth/web_identity.rb
Overview
private_key_jwt credential (RFC 7523) with auto-managed asymmetric keys: generates and persists an RSA-2048 keypair on first use, signs a short-lived client assertion on every token request, and exposes the public JWKS for the authorization server to verify. The recommended credential for production workloads that can persist a keypair; the private key never leaves the workload.
Holds no shared secret and contributes no Basic header. Never reads environment variables; the caller supplies storage configuration.
Instance Method Summary collapse
-
#authorization_header(issuer: nil) ⇒ nil
Assertion-based authentication contributes no Basic header.
-
#client_jwks_url(base_url) ⇒ String
The conventional URL where this workload serves its public JWKS.
-
#initialize(client_id:, server_name: nil, key_id: nil, storage: nil, storage_dir: nil, clock: -> { Time.now }) ⇒ WebIdentity
constructor
A new instance of WebIdentity.
-
#key_id ⇒ String
The key id used as the assertion's kid.
-
#prepare_token_exchange_request(subject_token:, token_endpoint: nil, resource: nil, audience: nil, scope: nil, issuer: nil) ⇒ Hash
Build the token-exchange form parameters, signing a fresh client assertion for this request.
-
#public_jwks ⇒ Hash
The public JWKS the authorization server verifies assertions against.
Constructor Details
#initialize(client_id:, server_name: nil, key_id: nil, storage: nil, storage_dir: nil, clock: -> { Time.now }) ⇒ WebIdentity
Returns a new instance of WebIdentity.
27 28 29 30 31 32 33 34 35 36 37 |
# File 'lib/keycardai/oauth/web_identity.rb', line 27 def initialize(client_id:, server_name: nil, key_id: nil, storage: nil, storage_dir: nil, clock: -> { Time.now }) raise ConfigurationError, "WebIdentity requires a client_id" if client_id.nil? || client_id.empty? @client_id = client_id storage ||= FilePrivateKeyStorage.new(dir: storage_dir || FilePrivateKeyStorage::DEFAULT_DIR) @key_manager = PrivateKeyManager.new( key_id: key_id || sanitize(server_name) || SecureRandom.uuid, storage: storage, clock: clock ) end |
Instance Method Details
#authorization_header(issuer: nil) ⇒ nil
Assertion-based authentication contributes no Basic header.
48 49 50 |
# File 'lib/keycardai/oauth/web_identity.rb', line 48 def (issuer: nil) nil end |
#client_jwks_url(base_url) ⇒ String
The conventional URL where this workload serves its public JWKS.
93 94 95 |
# File 'lib/keycardai/oauth/web_identity.rb', line 93 def client_jwks_url(base_url) "#{base_url.chomp("/")}/.well-known/jwks.json" end |
#key_id ⇒ String
Returns the key id used as the assertion's kid.
40 41 42 |
# File 'lib/keycardai/oauth/web_identity.rb', line 40 def key_id @key_manager.key_id end |
#prepare_token_exchange_request(subject_token:, token_endpoint: nil, resource: nil, audience: nil, scope: nil, issuer: nil) ⇒ Hash
Build the token-exchange form parameters, signing a fresh client assertion for this request.
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
# File 'lib/keycardai/oauth/web_identity.rb', line 63 def prepare_token_exchange_request(subject_token:, token_endpoint: nil, resource: nil, audience: nil, scope: nil, issuer: nil) if token_endpoint.nil? || token_endpoint.empty? raise ConfigurationError, "WebIdentity requires the token_endpoint as the assertion audience" end { "grant_type" => GrantType::TOKEN_EXCHANGE, "subject_token" => subject_token, "subject_token_type" => TokenType::ACCESS_TOKEN, "resource" => resource, "audience" => audience, "scope" => scope, "client_assertion" => @key_manager.create_client_assertion(client_id: @client_id, audience: token_endpoint), "client_assertion_type" => PrivateKeyManager::ASSERTION_TYPE }.compact end |
#public_jwks ⇒ Hash
The public JWKS the authorization server verifies assertions against.
85 86 87 |
# File 'lib/keycardai/oauth/web_identity.rb', line 85 def public_jwks @key_manager.public_jwks end |