Class: RubyOidcClient::IDPartner
- Inherits:
-
Object
- Object
- RubyOidcClient::IDPartner
- Defined in:
- lib/id_partner.rb
Constant Summary collapse
- SUPPORTED_AUTH_METHODS =
[ "client_secret_basic", "tls_client_auth", "private_key_jwt" # For backward compatibility ].freeze
- SIGNING_ALG =
"PS256"
- ENCRYPTION_ALG =
"RSA-OAEP"
- ENCRYPTION_ENC =
"A256CBC-HS512"
Instance Attribute Summary collapse
-
#config ⇒ Object
readonly
Returns the value of attribute config.
-
#endpoints ⇒ Object
readonly
Returns the value of attribute endpoints.
-
#provider_keys ⇒ Object
readonly
Returns the value of attribute provider_keys.
Instance Method Summary collapse
- #generate_proofs ⇒ Object
- #get_authorization_url(query, proofs, scope, extra_authorization_params = {}) ⇒ Object
-
#initialize(config) ⇒ IDPartner
constructor
A new instance of IDPartner.
- #public_jwks ⇒ Object
- #token(query, proofs) ⇒ Object
- #userinfo(access_token) ⇒ Object
Constructor Details
#initialize(config) ⇒ IDPartner
Returns a new instance of IDPartner.
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
# File 'lib/id_partner.rb', line 22 def initialize(config) raise ArgumentError, "Config missing." unless config default_config = { account_selector_service_url: "https://auth-api.idpartner.com/oidc-proxy", token_endpoint_auth_method: "client_secret_basic", jwks: nil, client_secret: nil } @config = default_config.merge(config) unless SUPPORTED_AUTH_METHODS.include?(@config[:token_endpoint_auth_method]) raise ArgumentError, "Unsupported token_endpoint_auth_method '#{config[:token_endpoint_auth_method]}'. It must be one of (#{SUPPORTED_AUTH_METHODS.join(", ")})" end client_secret_config = @config[:token_endpoint_auth_method] == "client_secret_basic" ? { client_secret: @config[:client_secret] } : {} jwks_config = if @config[:jwks] { authorization_encrypted_response_alg: ENCRYPTION_ALG, authorization_encrypted_response_enc: ENCRYPTION_ENC, id_token_encrypted_response_alg: ENCRYPTION_ALG, id_token_encrypted_response_enc: ENCRYPTION_ENC, request_object_signing_alg: SIGNING_ALG } else {} end @config = @config.merge({ authorization_signed_response_alg: SIGNING_ALG, id_token_signed_response_alg: SIGNING_ALG }).merge(client_secret_config).merge(jwks_config) end |
Instance Attribute Details
#config ⇒ Object (readonly)
Returns the value of attribute config.
20 21 22 |
# File 'lib/id_partner.rb', line 20 def config @config end |
#endpoints ⇒ Object (readonly)
Returns the value of attribute endpoints.
20 21 22 |
# File 'lib/id_partner.rb', line 20 def endpoints @endpoints end |
#provider_keys ⇒ Object (readonly)
Returns the value of attribute provider_keys.
20 21 22 |
# File 'lib/id_partner.rb', line 20 def provider_keys @provider_keys end |
Instance Method Details
#generate_proofs ⇒ Object
59 60 61 62 63 64 65 |
# File 'lib/id_partner.rb', line 59 def generate_proofs { state: SecureRandom.urlsafe_base64(64), nonce: SecureRandom.urlsafe_base64(64), code_verifier: SecureRandom.urlsafe_base64(64) } end |
#get_authorization_url(query, proofs, scope, extra_authorization_params = {}) ⇒ Object
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
# File 'lib/id_partner.rb', line 67 def (query, proofs, scope, = {}) raise ArgumentError, "The URL query parameter is required." unless query raise ArgumentError, "The scope parameter is required." unless scope raise ArgumentError, "The proofs parameter is required." unless proofs if query[:iss].nil? return "#{config[:account_selector_service_url]}/auth/select-accounts?client_id=#{config[:client_id]}&visitor_id=#{query[:visitor_id]}&scope=#{scope}&claims=#{extract_claims([:claims]).join("+")}" end @config[:iss] = query[:iss] obtain_well_known_config_endpoints [:claims] = [:claims]&.to_json = { redirect_uri: config[:redirect_uri], code_challenge_method: "S256", code_challenge: generate_code_challenge(proofs[:code_verifier]), state: proofs[:state], nonce: proofs[:nonce], scope: scope, response_type: "code", client_id: config[:client_id], 'x-fapi-interaction-id': SecureRandom.uuid, identity_provider_id: query[:idp_id], idpartner_token: query[:idpartner_token], response_mode: "jwt" }.merge().compact = = { request: create_request_object() } if config[:jwks] request_uri = ()["request_uri"] query_params = URI.encode_www_form(request_uri: request_uri) "#{endpoints[:authorization_endpoint]}?#{query_params}" end |
#public_jwks ⇒ Object
103 104 105 106 107 108 109 110 111 112 113 |
# File 'lib/id_partner.rb', line 103 def public_jwks return {} unless config[:jwks] jwk_set = JSON::JWK::Set.new(JSON.parse(config[:jwks])) public_jwks = jwk_set.collect do |jwk| public_jwk = jwk.to_key.public_key.to_jwk public_jwk.merge("alg" => jwk["alg"], "use" => jwk["use"]).compact end { "keys" => public_jwks } end |
#token(query, proofs) ⇒ Object
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 |
# File 'lib/id_partner.rb', line 115 def token(query, proofs) decoded_jwt = decode_jwt(query[:response]) basic_auth_credentials = Base64.strict_encode64("#{config[:client_id]}:#{config[:client_secret]}") payload = { code: decoded_jwt["code"], code_verifier: proofs[:code_verifier], grant_type: "authorization_code", redirect_uri: config[:redirect_uri] } uri = URI(endpoints[:token_endpoint]) http = Net::HTTP.new(uri.host, uri.port) headers = { "Authorization" => "Basic #{basic_auth_credentials}", "Content-Type" => "application/x-www-form-urlencoded", "Accept" => "application/json" } token_request = Net::HTTP::Post.new(uri.request_uri, headers) token_request.set_form_data(payload) token_response = http.request(token_request) raise "Failed to exchange token: #{token_response.body}" unless token_response.is_a?(Net::HTTPSuccess) JSON.parse(token_response.body) end |
#userinfo(access_token) ⇒ Object
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 |
# File 'lib/id_partner.rb', line 140 def userinfo(access_token) uri = URI(endpoints[:userinfo_endpoint]) http = Net::HTTP.new(uri.host, uri.port) headers = { "Authorization" => "Bearer #{access_token}", "Accept" => "application/json" } userinfo_request = Net::HTTP::Get.new(uri.request_uri, headers) userinfo_response = http.request(userinfo_request) raise "Failed to retrieve userinfo: #{userinfo_response.body}" unless userinfo_response.is_a?(Net::HTTPSuccess) JSON.parse(userinfo_response.body) rescue StandardError => e raise "Failed to fetch well-known config: #{e.}" end |