Class: Keycardai::OAuth::ClientSecret
- Inherits:
-
Object
- Object
- Keycardai::OAuth::ClientSecret
- Defined in:
- lib/keycardai/oauth/client_secret.rb
Overview
Static client_id + client_secret credential, authenticating with client_secret_basic (RFC 6749 ยง2.3.1 / RFC 7617). The simplest credential type, suitable for development and workloads that can safely hold a long-lived secret.
Implements the Credential interface: authorization_header(issuer:) plus prepare_token_exchange_request. Never reads environment variables; the caller sources the secret from its own config or secret manager.
Single zone:
ClientSecret.new("client_abc", "secret")
Multi-zone, keyed by the zone's issuer URL:
ClientSecret.new(
"https://acme.keycard.cloud" => ["client_a", "secret_a"],
"https://beta.keycard.cloud" => ["client_b", "secret_b"],
)
A token operation for a zone not in the map fails closed: the credential raises rather than fall back to another zone's secret.
Instance Method Summary collapse
-
#authorization_header(issuer: nil) ⇒ String
The HTTP Basic Authorization header for a token operation.
-
#initialize(client_id_or_map, client_secret = nil) ⇒ ClientSecret
constructor
A new instance of ClientSecret.
-
#issuers ⇒ Array<String>
The issuer URLs this credential can serve.
-
#multi_zone? ⇒ Boolean
Whether this credential holds per-zone pairs.
-
#prepare_token_exchange_request(subject_token:, resource: nil, audience: nil, scope: nil, token_endpoint: nil, issuer: nil) ⇒ Hash
Build the token-exchange form parameters.
Constructor Details
#initialize(client_id, client_secret) ⇒ ClientSecret #initialize(issuer_map) ⇒ ClientSecret
Returns a new instance of ClientSecret.
30 31 32 33 34 35 36 37 38 39 40 41 42 |
# File 'lib/keycardai/oauth/client_secret.rb', line 30 def initialize(client_id_or_map, client_secret = nil) if client_id_or_map.is_a?(Hash) raise ConfigurationError, "multi-zone ClientSecret requires at least one zone" if client_id_or_map.empty? @pairs = client_id_or_map.to_h do |issuer, (id, secret)| validate_pair(id, secret) [issuer.chomp("/"), [id, secret]] end else validate_pair(client_id_or_map, client_secret) @pair = [client_id_or_map, client_secret] end end |
Instance Method Details
#authorization_header(issuer: nil) ⇒ String
The HTTP Basic Authorization header for a token operation.
60 61 62 63 |
# File 'lib/keycardai/oauth/client_secret.rb', line 60 def (issuer: nil) client_id, client_secret = resolve_pair(issuer) HTTP.(client_id, client_secret) end |
#issuers ⇒ Array<String>
Returns the issuer URLs this credential can serve.
50 51 52 |
# File 'lib/keycardai/oauth/client_secret.rb', line 50 def issuers multi_zone? ? @pairs.keys : [] end |
#multi_zone? ⇒ Boolean
Returns whether this credential holds per-zone pairs.
45 46 47 |
# File 'lib/keycardai/oauth/client_secret.rb', line 45 def multi_zone? !@pairs.nil? end |
#prepare_token_exchange_request(subject_token:, resource: nil, audience: nil, scope: nil, token_endpoint: nil, issuer: nil) ⇒ Hash
Build the token-exchange form parameters. Client authentication rides in the Basic header, never in the body.
75 76 77 78 79 80 81 82 83 84 85 |
# File 'lib/keycardai/oauth/client_secret.rb', line 75 def prepare_token_exchange_request(subject_token:, resource: nil, audience: nil, scope: nil, token_endpoint: nil, issuer: nil) { "grant_type" => GrantType::TOKEN_EXCHANGE, "subject_token" => subject_token, "subject_token_type" => TokenType::ACCESS_TOKEN, "resource" => resource, "audience" => audience, "scope" => scope }.compact end |