ruby_oidc_client 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 5b5f37ec00ec2675db46405e2ae66bbb0575039bdf0de00ac5f2a9f9420360de
4
+ data.tar.gz: 86093df21b39985900be9a4fcba7c831bdcb64331759c63f2acd13a8f93787a4
5
+ SHA512:
6
+ metadata.gz: 5eb4f9337b6f5dfde2a008c544fd2a706ab58d81ee23ab2618cc36cd5376ec4840c94c2169ec32ce37a85a5c9efec742749a575b2f75e5a0cc23b5ad9d7d9f88
7
+ data.tar.gz: 137967b68fddf32d29a0bcd69923297aec3eb5ef8ff89e347db096ce10b49ea116004a5380038023e273eec25df9b04bf55c5c0f145d20cb249bff3b9d713d76
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,13 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.6
3
+
4
+ Style/StringLiterals:
5
+ Enabled: true
6
+ EnforcedStyle: double_quotes
7
+
8
+ Style/StringLiteralsInInterpolation:
9
+ Enabled: true
10
+ EnforcedStyle: double_quotes
11
+
12
+ Layout/LineLength:
13
+ Max: 120
data/CHANGELOG.md ADDED
@@ -0,0 +1,23 @@
1
+ 0.1.0
2
+
3
+ - Flexible Configuration:
4
+ - Supports various authentication methods including client_secret_basic and private_key_jwt.
5
+ - Configurable token endpoint auth method.
6
+ - Configurable JWKS for signing and encryption.
7
+ - Authorization:
8
+ - Generation of authorization URL with support for different scopes, and parameters like scope and claims.
9
+ - Support for both standard and pushed authorization requests.
10
+ - Generation of proofs including state, nonce, and code verifier for PKCE.
11
+ - Token Acquisition:
12
+ - Token exchange functionality for obtaining tokens from an authorization code.
13
+ - User Information Retrieval:
14
+ - Userinfo endpoint interaction to retrieve user information using an access token.
15
+ - JWT Handling:
16
+ - JWT decoding support including handling of encrypted JWTs.
17
+ - JWT signing and encryption support.
18
+ - Utilities:
19
+ - Fetching provider configuration from the well-known configuration endpoint.
20
+ - Error Handling:
21
+ - Comprehensive error handling for various steps in the OIDC interaction process.
22
+ - Example:
23
+ - Sinatra example usage provided in the examples folder demonstrating how to use the IDPartner class for OIDC interactions.
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2023 IDPartner
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,52 @@
1
+ # RubyOidcClient
2
+
3
+ RubyOidcClient is a Ruby gem that simplifies OpenID Connect client operations. This gem provides a set of functionalities to interact with OIDC providers, facilitating authentication and authorization processes.
4
+
5
+ ## Installation
6
+
7
+ You can install the `ruby_oidc_client` gem by executing the following command:
8
+
9
+ ```bash
10
+ $ gem install ruby_oidc_client
11
+ ```
12
+
13
+ Alternatively, if you are using Bundler, add this line to your application's Gemfile:
14
+
15
+ ```ruby
16
+ gem 'ruby_oidc_client'
17
+ ```
18
+
19
+ And then execute:
20
+
21
+ ```bash
22
+ $ bundle install
23
+ ```
24
+
25
+ ## Usage
26
+
27
+ Please check the [examples folder](./examples/)
28
+
29
+ ### Running Tests
30
+
31
+ After checking out the repo, install the necessary dependencies and run the tests by executing:
32
+
33
+ ```bash
34
+ $ rspec
35
+ ```
36
+
37
+ ### Running RuboCop
38
+
39
+ To check the code for styling issues according to the RuboCop guidelines, run:
40
+
41
+ ```bash
42
+ $ rubocop
43
+ ```
44
+
45
+ ## Contributing
46
+
47
+ Bug reports and pull requests are welcome on GitHub at [https://github.com/idpartner-app/ruby_oidc_client](https://github.com/idpartner-app/ruby_oidc_client).
48
+
49
+ ## License
50
+
51
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
52
+ ```
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ require "rubocop/rake_task"
9
+
10
+ RuboCop::RakeTask.new
11
+
12
+ task default: %i[spec rubocop]
@@ -0,0 +1,3 @@
1
+ # IDPartner examples
2
+
3
+ This contains the an example with the [ruby_oidc_client](https://github.com/idpartner-app/ruby_oidc_client) library, called [client-secret-basic](./client-secret-basic/README.md), which is a sinatra project using the client_secret_basic authentication method to obtain user info
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "sinatra"
6
+ gem "webrick"
@@ -0,0 +1,26 @@
1
+ GEM
2
+ remote: https://rubygems.org/
3
+ specs:
4
+ mustermann (3.0.0)
5
+ ruby2_keywords (~> 0.0.1)
6
+ rack (2.2.8)
7
+ rack-protection (3.1.0)
8
+ rack (~> 2.2, >= 2.2.4)
9
+ ruby2_keywords (0.0.5)
10
+ sinatra (3.1.0)
11
+ mustermann (~> 3.0)
12
+ rack (~> 2.2, >= 2.2.4)
13
+ rack-protection (= 3.1.0)
14
+ tilt (~> 2.0)
15
+ tilt (2.3.0)
16
+ webrick (1.8.1)
17
+
18
+ PLATFORMS
19
+ x86_64-darwin-23
20
+
21
+ DEPENDENCIES
22
+ sinatra
23
+ webrick
24
+
25
+ BUNDLED WITH
26
+ 2.4.21
@@ -0,0 +1,24 @@
1
+ # client_secret_basic flow using ruby_oidc_client lib
2
+
3
+ ## Prerequisites
4
+
5
+ 1. [Create an IDPartner Account](https://console.idpartner.com).
6
+ 1. [Create an Application (Client Secret)](https://docs.idpartner.com/documentation/relying-party-user-guide/registering-your-app#create-an-application).
7
+ 1. Ensure the following properties are set:
8
+ - Origin URL: http://localhost:3001/button/oauth
9
+ - Redirect URL: http://localhost:3001/button/oauth/callback
10
+ 1. Grab the "Client ID" and the "Client Secret" to update the following parts in your code:
11
+ 1. [Update CHANGE_ME_CLIENT_ID in the configuration file](./config.json)
12
+ 1. [Update CHANGE_ME_CLIENT_SECRET in the configuration file](./config.json)
13
+
14
+ Aditionally you optionally can configure the next steps:
15
+ 1. [Update the "redirect_uri" in the configuration file](./config.json)
16
+
17
+ ## Running the project
18
+
19
+ 1. Run: `bundle`
20
+ 1. Run: `ruby app.rb`
21
+ 1. Access http://localhost:3001
22
+ 1. Click the "Choose your ID Partner" button
23
+ 1. Search for "Mikomo Bank"
24
+ 1. Use these test credentials `mikomo_10/mikomo_10`
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "sinatra"
4
+ require_relative "../../lib/id_partner"
5
+
6
+ class App < Sinatra::Base
7
+ config = JSON.parse(File.read("config.json"))
8
+
9
+ set :bind, "0.0.0.0"
10
+ set :port, config["port"]
11
+ set :public_folder, "#{File.dirname(__FILE__)}/public"
12
+ enable :sessions
13
+
14
+ id_partner = RubyOidcClient::IDPartner.new({
15
+ client_id: config["client_id"],
16
+ client_secret: config["client_secret"],
17
+ redirect_uri: config["redirect_uri"]
18
+ })
19
+
20
+ get "/" do
21
+ erb :index, locals: { title: "RP Client Secret Example", config: config }
22
+ end
23
+
24
+ get "/button/oauth" do
25
+ scope = config["scope"]
26
+ proofs = id_partner.generate_proofs
27
+ session[:proofs] = proofs
28
+ session[:issuer] = params[:iss]
29
+ redirect id_partner.get_authorization_url(params, proofs, scope, { prompt: "consent" })
30
+ end
31
+
32
+ get "/button/oauth/callback" do
33
+ token = id_partner.token(params, session[:proofs])
34
+ userinfo = id_partner.userinfo(token["access_token"])
35
+ content_type :json
36
+ userinfo.to_json
37
+ end
38
+
39
+ get "/jwks" do
40
+ content_type :json
41
+ id_partner.public_jwks.to_json
42
+ end
43
+
44
+ run! if app_file == $PROGRAM_NAME
45
+ end
@@ -0,0 +1,7 @@
1
+ {
2
+ "client_id": "CHANGE_ME_CLIENT_ID",
3
+ "client_secret": "CHANGE_ME_CLIENT_SECRET",
4
+ "redirect_uri": "http://localhost:3001/button/oauth/callback",
5
+ "scope": "openid offline_access email profile birthdate address",
6
+ "port": 3001
7
+ }
@@ -0,0 +1,8 @@
1
+ body {
2
+ padding: 50px;
3
+ font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;
4
+ }
5
+
6
+ a {
7
+ color: #00B7FF;
8
+ }
@@ -0,0 +1,11 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <script src="https://install.idpartner.com/script.js"></script>
5
+ <title><%= title %></title>
6
+ <link rel='stylesheet' href='/stylesheets/style.css' />
7
+ </head>
8
+ <body>
9
+ <id-partner id="<%= config["client_id"] %>"></id-partner>
10
+ </body>
11
+ </html>
data/lib/id_partner.rb ADDED
@@ -0,0 +1,260 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "ruby_oidc_client/version"
4
+ require "json/jwt"
5
+ require "net/http"
6
+ require "uri"
7
+ require "base64"
8
+
9
+ module RubyOidcClient
10
+ class IDPartner
11
+ SUPPORTED_AUTH_METHODS = [
12
+ "client_secret_basic",
13
+ "tls_client_auth",
14
+ "private_key_jwt" # For backward compatibility
15
+ ].freeze
16
+ SIGNING_ALG = "PS256"
17
+ ENCRYPTION_ALG = "RSA-OAEP"
18
+ ENCRYPTION_ENC = "A256CBC-HS512"
19
+
20
+ attr_reader :config, :endpoints, :provider_keys
21
+
22
+ def initialize(config)
23
+ raise ArgumentError, "Config missing." unless config
24
+
25
+ default_config = {
26
+ account_selector_service_url: "https://auth-api.idpartner.com/oidc-proxy",
27
+ token_endpoint_auth_method: "client_secret_basic",
28
+ jwks: nil,
29
+ client_secret: nil
30
+ }
31
+
32
+ @config = default_config.merge(config)
33
+
34
+ unless SUPPORTED_AUTH_METHODS.include?(@config[:token_endpoint_auth_method])
35
+ raise ArgumentError,
36
+ "Unsupported token_endpoint_auth_method '#{config[:token_endpoint_auth_method]}'. It must be one of (#{SUPPORTED_AUTH_METHODS.join(", ")})"
37
+ end
38
+
39
+ client_secret_config = @config[:token_endpoint_auth_method] == "client_secret_basic" ? { client_secret: @config[:client_secret] } : {}
40
+
41
+ jwks_config = if @config[:jwks]
42
+ {
43
+ authorization_encrypted_response_alg: ENCRYPTION_ALG,
44
+ authorization_encrypted_response_enc: ENCRYPTION_ENC,
45
+ id_token_encrypted_response_alg: ENCRYPTION_ALG,
46
+ id_token_encrypted_response_enc: ENCRYPTION_ENC,
47
+ request_object_signing_alg: SIGNING_ALG
48
+ }
49
+ else
50
+ {}
51
+ end
52
+
53
+ @config = @config.merge({
54
+ authorization_signed_response_alg: SIGNING_ALG,
55
+ id_token_signed_response_alg: SIGNING_ALG
56
+ }).merge(client_secret_config).merge(jwks_config)
57
+ end
58
+
59
+ def generate_proofs
60
+ {
61
+ state: SecureRandom.urlsafe_base64(64),
62
+ nonce: SecureRandom.urlsafe_base64(64),
63
+ code_verifier: SecureRandom.urlsafe_base64(64)
64
+ }
65
+ end
66
+
67
+ def get_authorization_url(query, proofs, scope, extra_authorization_params = {})
68
+ raise ArgumentError, "The URL query parameter is required." unless query
69
+ raise ArgumentError, "The scope parameter is required." unless scope
70
+ raise ArgumentError, "The proofs parameter is required." unless proofs
71
+
72
+ if query[:iss].nil?
73
+ return "#{config[:account_selector_service_url]}/auth/select-accounts?client_id=#{config[:client_id]}&visitor_id=#{query[:visitor_id]}&scope=#{scope}&claims=#{extract_claims(extra_authorization_params[:claims]).join("+")}"
74
+ end
75
+
76
+ @config[:iss] = query[:iss]
77
+ obtain_well_known_config_endpoints
78
+
79
+ extra_authorization_params[:claims] = extra_authorization_params[:claims]&.to_json
80
+ extended_authorization_params = {
81
+ redirect_uri: config[:redirect_uri],
82
+ code_challenge_method: "S256",
83
+ code_challenge: generate_code_challenge(proofs[:code_verifier]),
84
+ state: proofs[:state],
85
+ nonce: proofs[:nonce],
86
+ scope: scope,
87
+ response_type: "code",
88
+ client_id: config[:client_id],
89
+ 'x-fapi-interaction-id': SecureRandom.uuid,
90
+ identity_provider_id: query[:idp_id],
91
+ idpartner_token: query[:idpartner_token],
92
+ response_mode: "jwt"
93
+ }.merge(extra_authorization_params).compact
94
+
95
+ pushed_authorization_request_params = extended_authorization_params
96
+ pushed_authorization_request_params = { request: create_request_object(extended_authorization_params) } if config[:jwks]
97
+
98
+ request_uri = push_authorization_request(pushed_authorization_request_params)["request_uri"]
99
+ query_params = URI.encode_www_form(request_uri: request_uri)
100
+ "#{endpoints[:authorization_endpoint]}?#{query_params}"
101
+ end
102
+
103
+ def public_jwks
104
+ return {} unless config[:jwks]
105
+
106
+ jwk_set = JSON::JWK::Set.new(JSON.parse(config[:jwks]))
107
+ public_jwks = jwk_set.collect do |jwk|
108
+ public_jwk = jwk.to_key.public_key.to_jwk
109
+ public_jwk.merge("alg" => jwk["alg"], "use" => jwk["use"]).compact
110
+ end
111
+
112
+ { "keys" => public_jwks }
113
+ end
114
+
115
+ def token(query, proofs)
116
+ decoded_jwt = decode_jwt(query[:response])
117
+ basic_auth_credentials = Base64.strict_encode64("#{config[:client_id]}:#{config[:client_secret]}")
118
+ payload = {
119
+ code: decoded_jwt["code"],
120
+ code_verifier: proofs[:code_verifier],
121
+ grant_type: "authorization_code",
122
+ redirect_uri: config[:redirect_uri]
123
+ }
124
+
125
+ uri = URI(endpoints[:token_endpoint])
126
+ http = Net::HTTP.new(uri.host, uri.port)
127
+ headers = {
128
+ "Authorization" => "Basic #{basic_auth_credentials}",
129
+ "Content-Type" => "application/x-www-form-urlencoded",
130
+ "Accept" => "application/json"
131
+ }
132
+ token_request = Net::HTTP::Post.new(uri.request_uri, headers)
133
+ token_request.set_form_data(payload)
134
+ token_response = http.request(token_request)
135
+ raise "Failed to exchange token: #{token_response.body}" unless token_response.is_a?(Net::HTTPSuccess)
136
+
137
+ JSON.parse(token_response.body)
138
+ end
139
+
140
+ def userinfo(access_token)
141
+ uri = URI(endpoints[:userinfo_endpoint])
142
+ http = Net::HTTP.new(uri.host, uri.port)
143
+ headers = {
144
+ "Authorization" => "Bearer #{access_token}",
145
+ "Accept" => "application/json"
146
+ }
147
+
148
+ userinfo_request = Net::HTTP::Get.new(uri.request_uri, headers)
149
+ userinfo_response = http.request(userinfo_request)
150
+
151
+ raise "Failed to retrieve userinfo: #{userinfo_response.body}" unless userinfo_response.is_a?(Net::HTTPSuccess)
152
+
153
+ JSON.parse(userinfo_response.body)
154
+ rescue StandardError => e
155
+ raise "Failed to fetch well-known config: #{e.message}"
156
+ end
157
+
158
+ private
159
+
160
+ def extract_claims(claims_object)
161
+ return [] unless claims_object.is_a?(Hash)
162
+
163
+ userinfo_keys = claims_object[:userinfo]&.keys || []
164
+ id_token_keys = claims_object[:id_token]&.keys || []
165
+
166
+ (userinfo_keys + id_token_keys).uniq
167
+ end
168
+
169
+ def obtain_well_known_config_endpoints
170
+ uri = URI("#{config[:iss]}/.well-known/openid-configuration")
171
+ http = Net::HTTP.new(uri.host, uri.port)
172
+ headers = { "Accept" => "application/json" }
173
+ request = Net::HTTP::Get.new(uri.request_uri, headers)
174
+ response = http.request(request)
175
+ raise "Failed to retrieve well-known: #{response.body}" unless response.is_a?(Net::HTTPSuccess)
176
+ well_known_config = JSON.parse(response.body)
177
+ @endpoints = {
178
+ authorization_endpoint: well_known_config["authorization_endpoint"],
179
+ token_endpoint: well_known_config["token_endpoint"],
180
+ userinfo_endpoint: well_known_config["userinfo_endpoint"],
181
+ pushed_authorization_request_endpoint: well_known_config["pushed_authorization_request_endpoint"],
182
+ jwks_uri: well_known_config["jwks_uri"]
183
+ }
184
+ rescue StandardError => e
185
+ raise "Failed to fetch well-known config: #{e.message}"
186
+ end
187
+
188
+ def create_request_object(params)
189
+ extended_params = params.merge({
190
+ iss: config[:client_id],
191
+ aud: config[:iss],
192
+ exp: Time.now.to_i + 60,
193
+ iat: Time.now.to_i,
194
+ nbf: Time.now.to_i
195
+ })
196
+
197
+ sig_key = sig_key()
198
+ jwt = JSON::JWT.new(extended_params)
199
+ jwt.sign(sig_key, sig_key["alg"]).to_s
200
+ end
201
+
202
+ def push_authorization_request(request_object)
203
+ uri = URI(endpoints[:pushed_authorization_request_endpoint])
204
+ http = Net::HTTP.new(uri.host, uri.port)
205
+ basic_auth_credentials = Base64.strict_encode64("#{config[:client_id]}:#{config[:client_secret]}")
206
+ headers = {
207
+ "Authorization" => "Basic #{basic_auth_credentials}",
208
+ "Content-Type" => "application/x-www-form-urlencoded",
209
+ "Accept" => "application/json"
210
+ }
211
+ par_request = Net::HTTP::Post.new(uri.request_uri, headers)
212
+ par_request.set_form_data(request_object)
213
+ par_response = http.request(par_request)
214
+ raise "Failed to push authorization request: #{par_response.body}" unless par_response.is_a?(Net::HTTPSuccess)
215
+
216
+ JSON.parse(par_response.body)
217
+ rescue StandardError => e
218
+ raise "An error occurred: #{e.message}"
219
+ end
220
+
221
+ def generate_code_challenge(code_verifier)
222
+ Base64.urlsafe_encode64(Digest::SHA256.digest(code_verifier)).gsub(/=+$/, "")
223
+ end
224
+
225
+ def sig_key
226
+ jwk_set = JSON::JWK::Set.new(JSON.parse(config[:jwks]))
227
+ jwk_set.find { |j| j[:use] == "sig" }
228
+ end
229
+
230
+ def enc_key
231
+ jwk_set = JSON::JWK::Set.new(JSON.parse(config[:jwks]))
232
+ jwk_set.find { |j| j[:use] == "enc" }
233
+ end
234
+
235
+ def decode_jwt(jwt_str)
236
+ if jwt_str.split(".").length == 5
237
+ jwe = JSON::JWT.decode(jwt_str, enc_key)
238
+ jwt_str = jwe.plain_text
239
+ end
240
+
241
+ kid = JSON::JWT.decode(jwt_str, :skip_verification).kid
242
+ sig_key = provider_key(kid)
243
+ JSON::JWT.decode(jwt_str, sig_key)
244
+ end
245
+
246
+ def provider_key(kid)
247
+ fetch_provider_keys unless provider_keys
248
+ @provider_keys[kid] || (raise "No provider key found for kid: #{kid}")
249
+ end
250
+
251
+ def fetch_provider_keys
252
+ jwks_uri = endpoints[:jwks_uri]
253
+ fetched_provider_keys = JSON::JWK::Set::Fetcher.fetch(jwks_uri, kid: nil, auto_detect: false)
254
+ @provider_keys = {}
255
+ fetched_provider_keys.each do |key|
256
+ @provider_keys[key["kid"]] = key
257
+ end
258
+ end
259
+ end
260
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyOidcClient
4
+ VERSION = "0.0.1"
5
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/ruby_oidc_client/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "ruby_oidc_client"
7
+ spec.version = RubyOidcClient::VERSION
8
+ spec.authors = ["Giovanni Alberto"]
9
+ spec.email = ["delirable@gmail.com"]
10
+
11
+ spec.summary = "A Ruby client for interacting with OpenID Connect providers using the IDPartner class."
12
+ spec.description = "The IDPartner gem provides a Ruby client for engaging with OpenID Connect providers, simplifying the process of authorization, token acquisition, and user information retrieval. It supports various authentication methods and handles endpoint discovery via well-known configuration. The gem encapsulates the complexities of generating, signing, and verifying JWTs, making OpenID Connect integration straightforward and secure."
13
+ spec.homepage = "https://github.com/idpartner-app/ruby_oidc_client"
14
+ spec.license = "MIT"
15
+ spec.required_ruby_version = ">= 2.6.0"
16
+
17
+ spec.metadata["allowed_push_host"] = "https://rubygems.org"
18
+
19
+ spec.metadata["homepage_uri"] = spec.homepage
20
+ spec.metadata["source_code_uri"] = "https://github.com/idpartner-app/ruby_oidc_client"
21
+ spec.metadata["changelog_uri"] = "https://github.com/idpartner-app/ruby_oidc_client/blob/master/CHANGELOG.md"
22
+
23
+ # Specify which files should be added to the gem when it is released.
24
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
25
+ spec.files = Dir.chdir(__dir__) do
26
+ `git ls-files -z`.split("\x0").reject do |f|
27
+ (File.expand_path(f) == __FILE__) ||
28
+ f.start_with?(*%w[bin/ test/ spec/ features/ .git .circleci appveyor Gemfile])
29
+ end
30
+ end
31
+ spec.bindir = "exe"
32
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
33
+ spec.require_paths = ["lib"]
34
+
35
+ # Uncomment to register a new dependency of your gem
36
+ spec.add_dependency "json-jwt", "~> 1.16.3"
37
+
38
+ # Optionally, within your gemspec file if you prefer to declare dev/test dependencies here
39
+ spec.add_development_dependency "rake", "~> 13.0"
40
+ spec.add_development_dependency "rspec", "~> 3.0"
41
+ spec.add_development_dependency "rubocop", "~> 1.21"
42
+ spec.add_development_dependency "vcr", "~> 6.2.0"
43
+ spec.add_development_dependency "webmock", "~> 3.19.1"
44
+
45
+ # For more information and examples about making a new gem, check out our
46
+ # guide at: https://bundler.io/guides/creating_gem.html
47
+ end
@@ -0,0 +1,40 @@
1
+ class IDPartner
2
+ type SUPPORTED_AUTH_METHODS: Array[String]
3
+ type SIGNING_ALG: String
4
+ type ENCRYPTION_ALG: String
5
+ type ENCRYPTION_ENC: String
6
+
7
+ attr_reader config: Hash[Symbol, String], endpoints: Hash[Symbol, String]
8
+
9
+ def initialize: (Hash[Symbol, String]) -> void
10
+
11
+ def generate_proofs: -> Hash[Symbol, String]
12
+
13
+ def get_authorization_url: (
14
+ query: Hash[Symbol, String],
15
+ proofs: Hash[Symbol, String],
16
+ scope: Array[String],
17
+ prompt: String,
18
+ claims_object: Hash[Symbol, String]
19
+ ) -> String
20
+
21
+ def get_public_jwks: -> Hash[String, Array[untyped]]
22
+
23
+ def token: (query: Hash[Symbol, String], proofs: Hash[Symbol, String]) -> Hash[String, String]
24
+
25
+ def userinfo: (String) -> Hash[String, String]
26
+
27
+ private
28
+
29
+ def get_endpoints_from_well_known_config: -> void
30
+
31
+ def create_request_object: (Hash[Symbol, untyped]) -> String
32
+
33
+ def push_authorization_request: (Hash[Symbol, untyped]) -> Hash[String, untyped]
34
+
35
+ def generate_code_challenge: (String) -> String
36
+
37
+ def parse_private_key: (String) -> untyped
38
+
39
+ def verify_jws: (String) -> Hash[Symbol, untyped]
40
+ end
metadata ADDED
@@ -0,0 +1,155 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ruby_oidc_client
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Giovanni Alberto
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2023-11-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: json-jwt
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 1.16.3
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 1.16.3
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '13.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '13.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rubocop
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.21'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.21'
69
+ - !ruby/object:Gem::Dependency
70
+ name: vcr
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 6.2.0
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 6.2.0
83
+ - !ruby/object:Gem::Dependency
84
+ name: webmock
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 3.19.1
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 3.19.1
97
+ description: The IDPartner gem provides a Ruby client for engaging with OpenID Connect
98
+ providers, simplifying the process of authorization, token acquisition, and user
99
+ information retrieval. It supports various authentication methods and handles endpoint
100
+ discovery via well-known configuration. The gem encapsulates the complexities of
101
+ generating, signing, and verifying JWTs, making OpenID Connect integration straightforward
102
+ and secure.
103
+ email:
104
+ - delirable@gmail.com
105
+ executables: []
106
+ extensions: []
107
+ extra_rdoc_files: []
108
+ files:
109
+ - ".rspec"
110
+ - ".rubocop.yml"
111
+ - CHANGELOG.md
112
+ - LICENSE.txt
113
+ - README.md
114
+ - Rakefile
115
+ - examples/README.md
116
+ - examples/client_secret_basic/Gemfile
117
+ - examples/client_secret_basic/Gemfile.lock
118
+ - examples/client_secret_basic/README.md
119
+ - examples/client_secret_basic/app.rb
120
+ - examples/client_secret_basic/config.json
121
+ - examples/client_secret_basic/public/stylesheets/style.css
122
+ - examples/client_secret_basic/views/index.erb
123
+ - lib/id_partner.rb
124
+ - lib/ruby_oidc_client/version.rb
125
+ - ruby_oidc_client.gemspec
126
+ - sig/ruby_oidc_client.rbs
127
+ homepage: https://github.com/idpartner-app/ruby_oidc_client
128
+ licenses:
129
+ - MIT
130
+ metadata:
131
+ allowed_push_host: https://rubygems.org
132
+ homepage_uri: https://github.com/idpartner-app/ruby_oidc_client
133
+ source_code_uri: https://github.com/idpartner-app/ruby_oidc_client
134
+ changelog_uri: https://github.com/idpartner-app/ruby_oidc_client/blob/master/CHANGELOG.md
135
+ post_install_message:
136
+ rdoc_options: []
137
+ require_paths:
138
+ - lib
139
+ required_ruby_version: !ruby/object:Gem::Requirement
140
+ requirements:
141
+ - - ">="
142
+ - !ruby/object:Gem::Version
143
+ version: 2.6.0
144
+ required_rubygems_version: !ruby/object:Gem::Requirement
145
+ requirements:
146
+ - - ">="
147
+ - !ruby/object:Gem::Version
148
+ version: '0'
149
+ requirements: []
150
+ rubygems_version: 3.4.10
151
+ signing_key:
152
+ specification_version: 4
153
+ summary: A Ruby client for interacting with OpenID Connect providers using the IDPartner
154
+ class.
155
+ test_files: []