Module: Privy::Authorization
- Defined in:
- lib/privy/authorization/authorization.rb,
lib/privy/authorization/canonicalization.rb
Defined Under Namespace
Modules: Canonicalization Classes: AuthorizationContext, PreparedRequest, WalletApiRequestSignatureInput
Class Method Summary collapse
- .format_request_for_authorization_signature(input) ⇒ Object
- .generate_authorization_signature(private_key_base64:, payload:) ⇒ Object
-
.generate_authorization_signatures(privy_client, input:, context:) ⇒ Object
Generates all authorization signatures for a request.
- .merge_prepared_headers!(params, headers) ⇒ Object
- .prepare_request(privy_client, method:, url:, body:, authorization_context: nil, idempotency_key: nil, request_expiry: nil) ⇒ Object
- .signed_url(privy_client, path) ⇒ Object
Class Method Details
.format_request_for_authorization_signature(input) ⇒ Object
47 48 49 50 51 52 53 54 55 56 |
# File 'lib/privy/authorization/authorization.rb', line 47 def (input) payload = { version: input.version, method: input.method, url: input.url, body: input.body.nil? || input.body == {} ? "" : input.body, headers: input.headers } Privy::Authorization::Canonicalization.canonicalize(payload).b end |
.generate_authorization_signature(private_key_base64:, payload:) ⇒ Object
58 59 60 61 62 63 |
# File 'lib/privy/authorization/authorization.rb', line 58 def (private_key_base64:, payload:) key = Privy::Cryptography.import_pkcs8_private_key(private_key_base64) digest = OpenSSL::Digest.new("SHA256").digest(payload) der = key.dsa_sign_asn1(digest) [der].pack("m0") end |
.generate_authorization_signatures(privy_client, input:, context:) ⇒ Object
Generates all authorization signatures for a request.
Signatures come from four sources, combined in this order:
-
Precomputed signatures passed directly in the context
-
Explicit private keys provided in authorization_private_keys
-
Private keys obtained by exchanging user JWTs via HPKE
-
Sign functions (callbacks that receive the canonicalized payload)
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/privy/authorization/authorization.rb', line 72 def (privy_client, input:, context:) if context.user_jwts.any? && privy_client.nil? raise ArgumentError, "privy_client is required when user_jwts are provided in the authorization context" end # Canonicalize the request into a deterministic byte string for signing payload = (input) # Exchange each user JWT for an ephemeral P-256 private key via HPKE. # Results are cached by JwtExchangeService so repeated calls are cheap. jwt_keys = context.user_jwts.map do |jwt| privy_client.jwt_exchange.(jwt) end all_private_keys = context. + jwt_keys key_sigs = all_private_keys.map do |pk| (private_key_base64: pk, payload: payload) end fn_sigs = context.sign_fns.map { |fn| fn.call(payload) } key_sigs + fn_sigs + context.signatures end |
.merge_prepared_headers!(params, headers) ⇒ Object
38 39 40 41 42 43 44 45 |
# File 'lib/privy/authorization/authorization.rb', line 38 def merge_prepared_headers!(params, headers) if headers["privy-authorization-signature"] params[:privy_authorization_signature] = headers["privy-authorization-signature"] end params[:privy_idempotency_key] = headers["privy-idempotency-key"] if headers["privy-idempotency-key"] params[:privy_request_expiry] = headers["privy-request-expiry"] if headers["privy-request-expiry"] end |
.prepare_request(privy_client, method:, url:, body:, authorization_context: nil, idempotency_key: nil, request_expiry: nil) ⇒ Object
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
# File 'lib/privy/authorization/authorization.rb', line 96 def prepare_request( privy_client, method:, url:, body:, authorization_context: nil, idempotency_key: nil, request_expiry: nil ) ctx = || AuthorizationContext.build headers = {} headers["privy-idempotency-key"] = idempotency_key if idempotency_key headers["privy-request-expiry"] = request_expiry.to_s if request_expiry signature_input = WalletApiRequestSignatureInput.build( method: method, url: url, body: body, headers: {"privy-app-id" => privy_client.app_id}.merge(headers) ) signatures = (privy_client, input: signature_input, context: ctx) headers["privy-authorization-signature"] = signatures.join(",") unless signatures.empty? PreparedRequest.new(headers: headers) end |
.signed_url(privy_client, path) ⇒ Object
33 34 35 36 |
# File 'lib/privy/authorization/authorization.rb', line 33 def signed_url(privy_client, path) base = privy_client.api.base_url.to_s.chomp("/") "#{base}/#{path}" end |