kinde_sdk 1.4.0 → 1.6.0
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 +4 -4
- data/kinde_api/spec/spec_helper.rb +1 -0
- data/lib/kinde_sdk/client.rb +1 -1
- data/lib/kinde_sdk/configuration.rb +8 -0
- data/lib/kinde_sdk/engine.rb +5 -0
- data/lib/kinde_sdk/version.rb +1 -1
- data/lib/kinde_sdk.rb +72 -1
- data/spec/kinde_sdk_spec.rb +44 -5
- data/spec/spec_helper.rb +3 -0
- metadata +45 -3
- data/lib/kinde_sdk/controllers/auth_controller.rb +0 -152
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 83f3ec0e5e4b6f61d409b0a6c6314459917c94fa6109440fda5634e7d2e747f6
|
4
|
+
data.tar.gz: 35dd34872266b28076bf0a9a89f5bb624d6a314d4067fc359a49f901403ef7a2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 58130b81b2d67b3c2ef8c4f34b6d87157016270b08af9d19d77bb67cfae9b27b32937bbd8b90891f0590b9ad7a7d4cdb0443cf4a2281983567c1960415f60bb8
|
7
|
+
data.tar.gz: fa2f18f0219dbe76661f9a6809deeb0a1e5fcfde13ea300533d3be8c342c97902143392e1c9991e3b94ad5bfda319eefb042f21de27405e091d7b6fbb2d34c75
|
data/lib/kinde_sdk/client.rb
CHANGED
@@ -10,6 +10,11 @@ module KindeSdk
|
|
10
10
|
attr_accessor :authorize_url
|
11
11
|
attr_accessor :token_url
|
12
12
|
|
13
|
+
attr_accessor :jwks_url
|
14
|
+
attr_accessor :jwks
|
15
|
+
attr_accessor :expected_issuer
|
16
|
+
attr_accessor :expected_audience
|
17
|
+
|
13
18
|
attr_accessor :logger
|
14
19
|
attr_accessor :debugging
|
15
20
|
attr_accessor :oauth_client
|
@@ -19,6 +24,9 @@ module KindeSdk
|
|
19
24
|
def initialize
|
20
25
|
@authorize_url = '/oauth2/auth'
|
21
26
|
@token_url = '/oauth2/token'
|
27
|
+
@jwks_url = '/.well-known/jwks.json'
|
28
|
+
@expected_audience = nil
|
29
|
+
@expected_issuer = nil
|
22
30
|
@debugging = false
|
23
31
|
@logger = defined?(Rails) ? Rails.logger : Logger.new(STDOUT)
|
24
32
|
@scope = 'openid offline email profile'
|
data/lib/kinde_sdk/version.rb
CHANGED
data/lib/kinde_sdk.rb
CHANGED
@@ -1,20 +1,28 @@
|
|
1
1
|
require "logger"
|
2
|
+
require "rails"
|
2
3
|
require "kinde_sdk/version"
|
3
4
|
require "kinde_sdk/configuration"
|
4
5
|
require "kinde_sdk/client/feature_flags"
|
5
6
|
require "kinde_sdk/client/permissions"
|
6
|
-
require "kinde_sdk/controllers/auth_controller"
|
7
7
|
require "kinde_sdk/client"
|
8
8
|
require 'securerandom'
|
9
9
|
require 'oauth2'
|
10
10
|
require 'pkce_challenge'
|
11
11
|
require 'faraday/follow_redirects'
|
12
12
|
require 'uri'
|
13
|
+
require 'httparty'
|
14
|
+
require 'jwt'
|
15
|
+
require 'openssl'
|
16
|
+
require 'base64'
|
13
17
|
|
14
18
|
module KindeSdk
|
15
19
|
class << self
|
16
20
|
attr_accessor :config
|
17
21
|
|
22
|
+
if defined?(Rails)
|
23
|
+
require "kinde_sdk/engine"
|
24
|
+
end
|
25
|
+
|
18
26
|
def configure
|
19
27
|
if block_given?
|
20
28
|
yield(Configuration.default)
|
@@ -102,6 +110,8 @@ module KindeSdk
|
|
102
110
|
#
|
103
111
|
# @return [KindeSdk::Client]
|
104
112
|
def client(tokens_hash)
|
113
|
+
validate_jwt_token(tokens_hash)
|
114
|
+
|
105
115
|
sdk_api_client = api_client(tokens_hash[:access_token] || tokens_hash["access_token"])
|
106
116
|
KindeSdk::Client.new(sdk_api_client, tokens_hash, @config.auto_refresh_tokens)
|
107
117
|
end
|
@@ -135,6 +145,8 @@ module KindeSdk
|
|
135
145
|
audience: "#{@config.domain}/api",
|
136
146
|
domain: @config.domain
|
137
147
|
)
|
148
|
+
validate_jwt_token(hash)
|
149
|
+
|
138
150
|
OAuth2::AccessToken.from_hash(@config.oauth_client(
|
139
151
|
client_id: client_id,
|
140
152
|
client_secret: client_secret,
|
@@ -150,6 +162,8 @@ module KindeSdk
|
|
150
162
|
audience: "#{@config.domain}/api",
|
151
163
|
domain: @config.domain
|
152
164
|
)
|
165
|
+
validate_jwt_token(hash)
|
166
|
+
|
153
167
|
OAuth2::AccessToken.from_hash(@config.oauth_client(
|
154
168
|
client_id: client_id,
|
155
169
|
client_secret: client_secret,
|
@@ -182,5 +196,62 @@ module KindeSdk
|
|
182
196
|
rescue URI::InvalidURIError
|
183
197
|
default_scheme
|
184
198
|
end
|
199
|
+
|
200
|
+
|
201
|
+
def validate_jwt_token(token_hash)
|
202
|
+
token_hash.each do |key, token|
|
203
|
+
next unless %w[access_token id_token].include?(key.to_s.downcase)
|
204
|
+
begin
|
205
|
+
jwt_validation(token, "#{@config.domain}#{@config.jwks_url}", @config.expected_issuer, @config.expected_audience)
|
206
|
+
rescue JWT::DecodeError
|
207
|
+
Rails.logger.error("Invalid JWT token: #{key}")
|
208
|
+
raise JWT::DecodeError, "Invalid #{key.to_s.capitalize.gsub('_', ' ')}"
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
|
214
|
+
# Method to validate a JWT token with caching for JWKS
|
215
|
+
def jwt_validation(jwt_token, jwks_url, expected_issuer, expected_audience)
|
216
|
+
@cached_jwks ||= fetch_jwks(jwks_url)
|
217
|
+
|
218
|
+
begin
|
219
|
+
validate_token(jwt_token, @cached_jwks, expected_issuer, expected_audience)
|
220
|
+
rescue JWT::DecodeError, StandardError
|
221
|
+
# If validation fails, fetch JWKS again and retry validation
|
222
|
+
@cached_jwks = fetch_jwks(jwks_url)
|
223
|
+
validate_token(jwt_token, @cached_jwks, expected_issuer, expected_audience)
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
private
|
228
|
+
|
229
|
+
# Fetch JWKS from the URL
|
230
|
+
def fetch_jwks(jwks_url)
|
231
|
+
jwks_response = HTTParty.get(jwks_url)
|
232
|
+
JSON.parse(jwks_response.body)
|
233
|
+
end
|
234
|
+
|
235
|
+
# Validate the JWT token using the provided JWKS
|
236
|
+
def validate_token(jwt_token, jwks_hash, expected_issuer, expected_audience)
|
237
|
+
# Decode token header to get 'kid'
|
238
|
+
decoded_token = JWT.decode(jwt_token, nil, false) # [payload, header]
|
239
|
+
header = decoded_token[1]
|
240
|
+
kid = header['kid']
|
241
|
+
|
242
|
+
# Find the matching JWK
|
243
|
+
jwks = JWT::JWK::Set.new(jwks_hash)
|
244
|
+
jwks.filter! {|key| key[:use] == 'sig' }
|
245
|
+
algorithms = jwks.map { |key| key[:alg] }.compact.uniq
|
246
|
+
payload, _header = JWT.decode(jwt_token, nil, true, algorithms: algorithms, jwks: jwks)
|
247
|
+
{ valid: true, payload: payload }
|
248
|
+
rescue JWT::DecodeError => e
|
249
|
+
Rails.logger.error("Token validation failed: #{e.message}")
|
250
|
+
raise JWT::DecodeError, "Token validation failed: #{e.message}"
|
251
|
+
rescue StandardError => e
|
252
|
+
Rails.logger.error("Unexpected error: #{e.message}")
|
253
|
+
raise StandardError, "Unexpected error: #{e.message}"
|
254
|
+
end
|
255
|
+
|
185
256
|
end
|
186
257
|
end
|
data/spec/kinde_sdk_spec.rb
CHANGED
@@ -1,4 +1,8 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
+
require 'jwt'
|
3
|
+
require 'openssl'
|
4
|
+
require 'webmock/rspec'
|
5
|
+
|
2
6
|
|
3
7
|
describe KindeSdk do
|
4
8
|
let(:domain) { "http://example.com" }
|
@@ -8,6 +12,13 @@ describe KindeSdk do
|
|
8
12
|
let(:logout_url) { "http://localhost/logout-callback" }
|
9
13
|
let(:auto_refresh_tokens) { true }
|
10
14
|
|
15
|
+
let(:optional_parameters) { { kid: 'my-kid', use: 'sig', alg: 'RS512' } }
|
16
|
+
let(:rsa_key) { OpenSSL::PKey::RSA.new(2048) }
|
17
|
+
let(:jwk) { JWT::JWK.new(rsa_key, optional_parameters) }
|
18
|
+
let(:payload) { { data: 'data' } }
|
19
|
+
let(:token) { JWT.encode(payload, jwk.signing_key, jwk[:alg], kid: jwk[:kid]) }
|
20
|
+
let(:jwks_hash) { JWT::JWK::Set.new(jwk).export }
|
21
|
+
|
11
22
|
before do
|
12
23
|
KindeSdk.configure do |c|
|
13
24
|
c.domain = domain
|
@@ -74,7 +85,19 @@ describe KindeSdk do
|
|
74
85
|
)
|
75
86
|
.to_return(
|
76
87
|
status: 200,
|
77
|
-
body: { "access_token"
|
88
|
+
body: { "access_token" => "eyJ", "id_token" => "test", "refresh_token" => "test", "expires_in" => 86399, "scope" => "", "token_type" => "bearer" }.to_json,
|
89
|
+
headers: { "content-type" => "application/json;charset=UTF-8" }
|
90
|
+
)
|
91
|
+
stub_request(:get, "#{domain}/.well-known/jwks.json")
|
92
|
+
.with(
|
93
|
+
headers: {
|
94
|
+
'Accept'=>'*/*',
|
95
|
+
'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
|
96
|
+
'User-Agent'=>'Ruby'
|
97
|
+
})
|
98
|
+
.to_return(
|
99
|
+
status: 200,
|
100
|
+
body: jwks_hash.to_json,
|
78
101
|
headers: { "content-type" => "application/json;charset=UTF-8" }
|
79
102
|
)
|
80
103
|
end
|
@@ -123,13 +146,13 @@ describe KindeSdk do
|
|
123
146
|
let(:hash_to_encode) do
|
124
147
|
{ "aud" => [],
|
125
148
|
"azp" => "19ebb687cd2f405c9f2daf645a8db895",
|
126
|
-
"exp" => 1679600554,
|
127
149
|
"feature_flags" => {
|
128
150
|
"asd" => { "t" => "b", "v" => true },
|
129
151
|
"eeeeee" => { "t" => "i", "v" => 111 },
|
130
152
|
"qqq" => { "t" => "s", "v" => "aa" }
|
131
153
|
},
|
132
|
-
"iat"
|
154
|
+
"iat": Time.now.to_i, # Issued at: current time
|
155
|
+
"exp": Time.now.to_i + 3600, # Expiration time: 1 hour from now
|
133
156
|
"iss" => "https://example.kinde.com",
|
134
157
|
"jti" => "22c48b2c-da46-4661-a7ff-425c23eceab5",
|
135
158
|
"org_code" => "org_cb4544175bc",
|
@@ -137,9 +160,23 @@ describe KindeSdk do
|
|
137
160
|
"scp" => ["openid", "offline"],
|
138
161
|
"sub" => "kp:b17adf719f7d4b87b611d1a88a09fd15" }
|
139
162
|
end
|
140
|
-
|
163
|
+
before do
|
164
|
+
stub_request(:get, "#{domain}/.well-known/jwks.json")
|
165
|
+
.with(
|
166
|
+
headers: {
|
167
|
+
'Accept'=>'*/*',
|
168
|
+
'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
|
169
|
+
'User-Agent'=>'Ruby'
|
170
|
+
})
|
171
|
+
.to_return(
|
172
|
+
status: 200,
|
173
|
+
body: jwks_hash.to_json,
|
174
|
+
headers: { "content-type" => "application/json;charset=UTF-8" }
|
175
|
+
)
|
176
|
+
end
|
177
|
+
let(:token) { JWT.encode(hash_to_encode, jwk.signing_key, jwk[:alg], kid: jwk[:kid]) }
|
141
178
|
let(:expires_at) { Time.now.to_i + 10000000 }
|
142
|
-
let(:client) { described_class.client({
|
179
|
+
let(:client) { described_class.client({ access_token: token, expires_at: expires_at }) }
|
143
180
|
|
144
181
|
context "with feature flags" do
|
145
182
|
it "returns existing flags", :aggregate_failures do
|
@@ -229,3 +266,5 @@ describe KindeSdk do
|
|
229
266
|
end
|
230
267
|
end
|
231
268
|
end
|
269
|
+
|
270
|
+
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kinde_sdk
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kinde Australia Pty Ltd
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-03-
|
11
|
+
date: 2025-03-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: typhoeus
|
@@ -72,6 +72,48 @@ dependencies:
|
|
72
72
|
- - ">="
|
73
73
|
- !ruby/object:Gem::Version
|
74
74
|
version: '0'
|
75
|
+
- !ruby/object:Gem::Dependency
|
76
|
+
name: rails
|
77
|
+
requirement: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - ">="
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: 7.0.4
|
82
|
+
type: :runtime
|
83
|
+
prerelease: false
|
84
|
+
version_requirements: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: 7.0.4
|
89
|
+
- !ruby/object:Gem::Dependency
|
90
|
+
name: httparty
|
91
|
+
requirement: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - "~>"
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: 0.19.0
|
96
|
+
type: :runtime
|
97
|
+
prerelease: false
|
98
|
+
version_requirements: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - "~>"
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: 0.19.0
|
103
|
+
- !ruby/object:Gem::Dependency
|
104
|
+
name: jwt
|
105
|
+
requirement: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - "~>"
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '2.2'
|
110
|
+
type: :runtime
|
111
|
+
prerelease: false
|
112
|
+
version_requirements: !ruby/object:Gem::Requirement
|
113
|
+
requirements:
|
114
|
+
- - "~>"
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: '2.2'
|
75
117
|
- !ruby/object:Gem::Dependency
|
76
118
|
name: rspec
|
77
119
|
requirement: !ruby/object:Gem::Requirement
|
@@ -422,7 +464,7 @@ files:
|
|
422
464
|
- lib/kinde_sdk/client/feature_flags.rb
|
423
465
|
- lib/kinde_sdk/client/permissions.rb
|
424
466
|
- lib/kinde_sdk/configuration.rb
|
425
|
-
- lib/kinde_sdk/
|
467
|
+
- lib/kinde_sdk/engine.rb
|
426
468
|
- lib/kinde_sdk/version.rb
|
427
469
|
- spec/kinde_sdk_spec.rb
|
428
470
|
- spec/spec_helper.rb
|
@@ -1,152 +0,0 @@
|
|
1
|
-
require 'action_controller'
|
2
|
-
require 'uri'
|
3
|
-
require 'cgi'
|
4
|
-
require 'net/http'
|
5
|
-
require 'json'
|
6
|
-
require 'jwt'
|
7
|
-
|
8
|
-
module KindeSdk
|
9
|
-
class AuthController < ActionController::Base
|
10
|
-
# Add before_action to validate nonce in callback
|
11
|
-
before_action :validate_state, only: :callback
|
12
|
-
|
13
|
-
def auth
|
14
|
-
# Generate a secure random nonce
|
15
|
-
nonce = SecureRandom.urlsafe_base64(16)
|
16
|
-
|
17
|
-
# Call KindeSdk.auth_url with nonce
|
18
|
-
auth_data = KindeSdk.auth_url(nonce: nonce)
|
19
|
-
|
20
|
-
# Store in session
|
21
|
-
session[:code_verifier] = auth_data[:code_verifier] if auth_data[:code_verifier].present?
|
22
|
-
session[:auth_nonce] = nonce
|
23
|
-
session[:auth_state] = {
|
24
|
-
requested_at: Time.current.to_i,
|
25
|
-
redirect_url: auth_data[:url]
|
26
|
-
}
|
27
|
-
|
28
|
-
redirect_to auth_data[:url], allow_other_host: true
|
29
|
-
end
|
30
|
-
|
31
|
-
def callback
|
32
|
-
tokens = KindeSdk.fetch_tokens(
|
33
|
-
params[:code],
|
34
|
-
code_verifier: KindeSdk.config.pkce_enabled ? session[:code_verifier] : nil
|
35
|
-
).slice(:access_token, :id_token, :refresh_token, :expires_at)
|
36
|
-
|
37
|
-
|
38
|
-
# Validate nonce in ID token
|
39
|
-
id_token = tokens[:id_token]
|
40
|
-
issuer = KindeSdk.config.domain
|
41
|
-
client_id = KindeSdk.config.client_id
|
42
|
-
original_nonce = session[:auth_nonce]
|
43
|
-
unless validate_nonce(id_token, original_nonce, issuer, client_id)
|
44
|
-
Rails.logger.warn("Nonce validation failed")
|
45
|
-
redirect_to "/", alert: "Invalid authentication nonce"
|
46
|
-
return
|
47
|
-
end
|
48
|
-
|
49
|
-
# Store tokens and user in session
|
50
|
-
session[:kinde_auth] = OAuth2::AccessToken.from_hash(KindeSdk.config.oauth_client, tokens).to_hash
|
51
|
-
.slice(:access_token, :refresh_token, :expires_at)
|
52
|
-
session[:kinde_user] = KindeSdk.client(tokens).oauth.get_user.to_hash
|
53
|
-
|
54
|
-
# Clear nonce and state after successful authentication
|
55
|
-
session.delete(:auth_nonce)
|
56
|
-
session.delete(:auth_state)
|
57
|
-
session.delete(:code_verifier)
|
58
|
-
redirect_to "/"
|
59
|
-
rescue StandardError => e
|
60
|
-
Rails.logger.error("Authentication callback failed: #{e.message}")
|
61
|
-
redirect_to "/", alert: "Authentication failed"
|
62
|
-
end
|
63
|
-
|
64
|
-
def client_credentials_auth
|
65
|
-
result = KindeSdk.client_credentials_access(
|
66
|
-
client_id: ENV["KINDE_MANAGEMENT_CLIENT_ID"],
|
67
|
-
client_secret: ENV["KINDE_MANAGEMENT_CLIENT_SECRET"]
|
68
|
-
)
|
69
|
-
|
70
|
-
if result["error"].present?
|
71
|
-
Rails.logger.error("Client credentials auth failed: #{result['error']}")
|
72
|
-
raise result["error"]
|
73
|
-
end
|
74
|
-
|
75
|
-
$redis.set("kinde_m2m_token", result["access_token"], ex: result["expires_in"].to_i)
|
76
|
-
redirect_to mgmt_path
|
77
|
-
end
|
78
|
-
|
79
|
-
def logout
|
80
|
-
redirect_to KindeSdk.logout_url, allow_other_host: true
|
81
|
-
end
|
82
|
-
|
83
|
-
def logout_callback
|
84
|
-
reset_session
|
85
|
-
redirect_to "/"
|
86
|
-
end
|
87
|
-
|
88
|
-
private
|
89
|
-
|
90
|
-
def validate_state
|
91
|
-
# Check if nonce and state exist in session
|
92
|
-
unless session[:auth_nonce] && session[:auth_state]
|
93
|
-
Rails.logger.warn("Missing session state or nonce")
|
94
|
-
redirect_to "/", alert: "Invalid authentication state"
|
95
|
-
return
|
96
|
-
end
|
97
|
-
|
98
|
-
# Verify nonce returned matches stored nonce
|
99
|
-
returned_state = params[:state]
|
100
|
-
stored_state = session[:auth_state]
|
101
|
-
stored_url = stored_state["redirect_url"]
|
102
|
-
|
103
|
-
# Extract the state from the stored redirect_url
|
104
|
-
parsed_url = URI.parse(stored_url)
|
105
|
-
query_params = CGI.parse(parsed_url.query || "")
|
106
|
-
stored_state_from_url = query_params["state"]&.first
|
107
|
-
|
108
|
-
# Verify returned state matches the state extracted from the redirect_url
|
109
|
-
unless returned_state.present? && returned_state == stored_state_from_url
|
110
|
-
Rails.logger.warn("State validation failed: returned=#{returned_state}, expected=#{stored_state_from_url}")
|
111
|
-
redirect_to "/", alert: "Invalid authentication state"
|
112
|
-
return
|
113
|
-
end
|
114
|
-
|
115
|
-
# Optional: Check state age (e.g., expires after 15 minutes)
|
116
|
-
if Time.current.to_i - stored_state["requested_at"] > 900
|
117
|
-
Rails.logger.warn("Authentication state expired")
|
118
|
-
redirect_to "/", alert: "Authentication session expired"
|
119
|
-
return
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
|
-
|
124
|
-
def validate_nonce(id_token, original_nonce, issuer, client_id)
|
125
|
-
jwks_uri = URI.parse("#{issuer}/.well-known/jwks.json")
|
126
|
-
jwks_response = Net::HTTP.get(jwks_uri)
|
127
|
-
jwks = JSON.parse(jwks_response)
|
128
|
-
|
129
|
-
decoded_token = JWT.decode(
|
130
|
-
id_token,
|
131
|
-
nil,
|
132
|
-
true,
|
133
|
-
algorithm: 'RS256',
|
134
|
-
iss: issuer,
|
135
|
-
aud: client_id,
|
136
|
-
verify_iss: true,
|
137
|
-
verify_aud: true,
|
138
|
-
jwks: { keys: jwks['keys'] }
|
139
|
-
)
|
140
|
-
|
141
|
-
payload = decoded_token[0]
|
142
|
-
nonce_from_token = payload['nonce']
|
143
|
-
|
144
|
-
nonce_from_token == original_nonce
|
145
|
-
rescue StandardError => e
|
146
|
-
Rails.logger.error("Nonce validation error: #{e.message}")
|
147
|
-
false
|
148
|
-
end
|
149
|
-
|
150
|
-
|
151
|
-
end
|
152
|
-
end
|