Class: Keycardai::OAuth::PrivateKeyManager
- Inherits:
-
Object
- Object
- Keycardai::OAuth::PrivateKeyManager
- Defined in:
- lib/keycardai/oauth/private_key.rb
Overview
Generates, persists, and loads an RSA-2048 keypair, and signs RFC 7523 private_key_jwt client assertions with it. WebIdentity composes this; it is also usable standalone.
Constant Summary collapse
- ASSERTION_TYPE =
"urn:ietf:params:oauth:client-assertion-type:jwt-bearer"- DEFAULT_ASSERTION_LIFETIME =
300
Instance Attribute Summary collapse
-
#key_id ⇒ String
readonly
The key id (the JWT kid).
Instance Method Summary collapse
-
#create_client_assertion(client_id:, audience:, expiry_seconds: DEFAULT_ASSERTION_LIFETIME) ⇒ String
Sign a short-lived client assertion (RFC 7523 §3).
-
#initialize(key_id:, storage: FilePrivateKeyStorage.new, clock: -> { Time.now }) ⇒ PrivateKeyManager
constructor
A new instance of PrivateKeyManager.
-
#key ⇒ OpenSSL::PKey::RSA
Load the persisted keypair, generating and storing one on first use.
-
#public_jwks ⇒ Hash
The public half as a JWKS document, for the authorization server to verify assertions against.
Constructor Details
#initialize(key_id:, storage: FilePrivateKeyStorage.new, clock: -> { Time.now }) ⇒ PrivateKeyManager
Returns a new instance of PrivateKeyManager.
57 58 59 60 61 62 63 |
# File 'lib/keycardai/oauth/private_key.rb', line 57 def initialize(key_id:, storage: FilePrivateKeyStorage.new, clock: -> { Time.now }) @key_id = key_id @storage = storage @clock = clock @key = nil @mutex = Mutex.new end |
Instance Attribute Details
#key_id ⇒ String (readonly)
Returns the key id (the JWT kid).
52 53 54 |
# File 'lib/keycardai/oauth/private_key.rb', line 52 def key_id @key_id end |
Instance Method Details
#create_client_assertion(client_id:, audience:, expiry_seconds: DEFAULT_ASSERTION_LIFETIME) ⇒ String
Sign a short-lived client assertion (RFC 7523 §3).
83 84 85 86 87 88 89 90 |
# File 'lib/keycardai/oauth/private_key.rb', line 83 def create_client_assertion(client_id:, audience:, expiry_seconds: DEFAULT_ASSERTION_LIFETIME) now = @clock.call.to_i claims = { "iss" => client_id, "sub" => client_id, "aud" => audience, "jti" => SecureRandom.uuid, "iat" => now, "exp" => now + expiry_seconds } JWTSigner.new(key: key, kid: @key_id).sign(claims) end |
#key ⇒ OpenSSL::PKey::RSA
Load the persisted keypair, generating and storing one on first use.
68 69 70 71 72 73 74 75 |
# File 'lib/keycardai/oauth/private_key.rb', line 68 def key @mutex.synchronize do @key ||= begin pem = @storage.load(@key_id) pem ? OpenSSL::PKey::RSA.new(pem) : generate end end end |
#public_jwks ⇒ Hash
The public half as a JWKS document, for the authorization server to verify assertions against.
96 97 98 99 |
# File 'lib/keycardai/oauth/private_key.rb', line 96 def public_jwks jwk = JWT::JWK.new(key.public_key, { kid: @key_id, use: "sig", alg: "RS256" }) { "keys" => [jwk.export.transform_keys(&:to_s)] } end |