rodauth-oauth 1.0.0.pre.beta1 → 1.0.0.pre.beta2

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.
@@ -17,6 +17,7 @@ module Rodauth
17
17
  issuer
18
18
  authorization_endpoint
19
19
  end_session_endpoint
20
+ backchannel_logout_session_supported
20
21
  token_endpoint
21
22
  userinfo_endpoint
22
23
  jwks_uri
@@ -74,10 +75,9 @@ module Rodauth
74
75
  auth_value_method :"oauth_applications_#{column}_column", column
75
76
  end
76
77
 
77
- auth_value_method :oauth_grants_nonce_column, :nonce
78
- auth_value_method :oauth_grants_acr_column, :acr
79
- auth_value_method :oauth_grants_nonce_column, :nonce
80
- auth_value_method :oauth_grants_acr_column, :acr
78
+ %i[nonce acr claims_locales claims].each do |column|
79
+ auth_value_method :"oauth_grants_#{column}_column", column
80
+ end
81
81
 
82
82
  auth_value_method :oauth_jwt_subject_type, "public" # fallback subject type: public, pairwise
83
83
  auth_value_method :oauth_jwt_subject_secret, nil # salt for pairwise generation
@@ -88,12 +88,10 @@ module Rodauth
88
88
  auth_value_method :oauth_prompt_login_cookie_options, {}.freeze
89
89
  auth_value_method :oauth_prompt_login_interval, 5 * 60 * 60 # 5 minutes
90
90
 
91
- # logout
92
- auth_value_method :oauth_applications_post_logout_redirect_uri_column, :post_logout_redirect_uri
93
- auth_value_method :use_rp_initiated_logout?, false
94
-
95
91
  auth_value_methods(
92
+ :oauth_acr_values_supported,
96
93
  :get_oidc_account_last_login_at,
94
+ :oidc_authorize_on_prompt_none?,
97
95
  :get_oidc_param,
98
96
  :get_additional_param,
99
97
  :require_acr_value_phr,
@@ -122,11 +120,28 @@ module Rodauth
122
120
 
123
121
  oidc_claims = { "sub" => claims["sub"] }
124
122
 
125
- fill_with_account_claims(oidc_claims, account, oauth_scopes)
126
-
127
123
  @oauth_application = db[oauth_applications_table].where(oauth_applications_client_id_column => claims["client_id"]).first
128
124
 
129
- if (algo = @oauth_application && @oauth_application[oauth_applications_userinfo_signed_response_alg_column])
125
+ throw_json_response_error(oauth_authorization_required_error_status, "invalid_token") unless @oauth_application
126
+
127
+ oauth_grant = valid_oauth_grant_ds(
128
+ oauth_grants_oauth_application_id_column => @oauth_application[oauth_applications_id_column],
129
+ oauth_grants_account_id_column => account[account_id_column]
130
+ ).first
131
+
132
+ claims_locales = oauth_grant[oauth_grants_claims_locales_column] if oauth_grant
133
+
134
+ if (claims = oauth_grant[oauth_grants_claims_column])
135
+ claims = JSON.parse(claims)
136
+ if (userinfo_essential_claims = claims["userinfo"])
137
+ oauth_scopes |= userinfo_essential_claims.to_a
138
+ end
139
+ end
140
+
141
+ # 5.4 - The Claims requested by the profile, email, address, and phone scope values are returned from the UserInfo Endpoint
142
+ fill_with_account_claims(oidc_claims, account, oauth_scopes, claims_locales)
143
+
144
+ if (algo = @oauth_application[oauth_applications_userinfo_signed_response_alg_column])
130
145
  params = {
131
146
  jwks: oauth_application_jwks(@oauth_application),
132
147
  encryption_algorithm: @oauth_application[oauth_applications_userinfo_encrypted_response_alg_column],
@@ -134,7 +149,12 @@ module Rodauth
134
149
  }.compact
135
150
 
136
151
  jwt = jwt_encode(
137
- oidc_claims,
152
+ oidc_claims.merge(
153
+ # If signed, the UserInfo Response SHOULD contain the Claims iss (issuer) and aud (audience) as members. The iss value
154
+ # SHOULD be the OP's Issuer Identifier URL. The aud value SHOULD be or include the RP's Client ID value.
155
+ iss: oauth_jwt_issuer,
156
+ aud: @oauth_application[oauth_applications_client_id_column]
157
+ ),
138
158
  signing_algorithm: algo,
139
159
  **params
140
160
  )
@@ -148,81 +168,6 @@ module Rodauth
148
168
  end
149
169
  end
150
170
 
151
- # /oidc-logout
152
- auth_server_route(:oidc_logout) do |r|
153
- next unless use_rp_initiated_logout?
154
-
155
- require_authorizable_account
156
- before_oidc_logout_route
157
-
158
- # OpenID Providers MUST support the use of the HTTP GET and POST methods
159
- r.on method: %i[get post] do
160
- catch_error do
161
- validate_oidc_logout_params
162
-
163
- #
164
- # why this is done:
165
- #
166
- # we need to decode the id token in order to get the application, because, if the
167
- # signing key is application-specific, we don't know how to verify the signature
168
- # beforehand. Hence, we have to do it twice: decode-and-do-not-verify, initialize
169
- # the @oauth_application, and then decode-and-verify.
170
- #
171
- claims = jwt_decode(param("id_token_hint"), verify_claims: false)
172
- oauth_application = db[oauth_applications_table].where(oauth_applications_client_id_column => claims["client_id"]).first
173
- oauth_grant = db[oauth_grants_table]
174
- .where(
175
- oauth_grants_oauth_application_id_column => oauth_application[oauth_applications_id_column],
176
- oauth_grants_account_id_column => account_id
177
- ).first
178
-
179
- # check whether ID token belongs to currently logged-in user
180
- redirect_response_error("invalid_request") unless oauth_grant && claims["sub"] == jwt_subject(
181
- oauth_grant, oauth_application
182
- )
183
-
184
- # When an id_token_hint parameter is present, the OP MUST validate that it was the issuer of the ID Token.
185
- redirect_response_error("invalid_request") unless claims && claims["iss"] == oauth_jwt_issuer
186
-
187
- # now let's logout from IdP
188
- transaction do
189
- before_logout
190
- logout
191
- after_logout
192
- end
193
-
194
- if (post_logout_redirect_uri = param_or_nil("post_logout_redirect_uri"))
195
- catch(:default_logout_redirect) do
196
- oauth_application = db[oauth_applications_table].where(oauth_applications_client_id_column => claims["client_id"]).first
197
-
198
- throw(:default_logout_redirect) unless oauth_application
199
-
200
- post_logout_redirect_uris = oauth_application[oauth_applications_post_logout_redirect_uri_column].split(" ")
201
-
202
- throw(:default_logout_redirect) unless post_logout_redirect_uris.include?(post_logout_redirect_uri)
203
-
204
- if (state = param_or_nil("state"))
205
- post_logout_redirect_uri = URI(post_logout_redirect_uri)
206
- params = ["state=#{state}"]
207
- params << post_logout_redirect_uri.query if post_logout_redirect_uri.query
208
- post_logout_redirect_uri.query = params.join("&")
209
- post_logout_redirect_uri = post_logout_redirect_uri.to_s
210
- end
211
-
212
- redirect(post_logout_redirect_uri)
213
- end
214
-
215
- end
216
-
217
- # regular logout procedure
218
- set_notice_flash(logout_notice_flash)
219
- redirect(logout_redirect)
220
- end
221
-
222
- redirect_response_error("invalid_request")
223
- end
224
- end
225
-
226
171
  def load_openid_configuration_route(alt_issuer = nil)
227
172
  request.on(".well-known/openid-configuration") do
228
173
  allow_cors(request)
@@ -260,7 +205,11 @@ module Rodauth
260
205
  end
261
206
 
262
207
  def oauth_response_types_supported
263
- super | %w[id_token none]
208
+ grant_types = oauth_grant_types_supported
209
+ oidc_response_types = %w[id_token none]
210
+ oidc_response_types |= ["code id_token"] if grant_types.include?("authorization_code")
211
+ oidc_response_types |= ["code token", "id_token token", "code id_token token"] if grant_types.include?("implicit")
212
+ super | oidc_response_types
264
213
  end
265
214
 
266
215
  def current_oauth_account
@@ -284,18 +233,62 @@ module Rodauth
284
233
  end
285
234
  end
286
235
 
236
+ def oauth_acr_values_supported
237
+ acr_values = []
238
+ acr_values << "phrh" if features.include?(:webauthn_login)
239
+ acr_values << "phr" if respond_to?(:require_two_factor_authenticated)
240
+ acr_values
241
+ end
242
+
243
+ def oidc_authorize_on_prompt_none?(_account)
244
+ false
245
+ end
246
+
287
247
  def validate_authorize_params
288
- return super unless (max_age = param_or_nil("max_age"))
248
+ if (max_age = param_or_nil("max_age"))
289
249
 
290
- max_age = Integer(max_age)
250
+ max_age = Integer(max_age)
291
251
 
292
- redirect_response_error("invalid_request") unless max_age.positive?
252
+ redirect_response_error("invalid_request") unless max_age.positive?
293
253
 
294
- if Time.now - get_oidc_account_last_login_at(session_value) > max_age
295
- # force user to re-login
296
- clear_session
297
- set_session_value(login_redirect_session_key, request.fullpath)
298
- redirect require_login_redirect
254
+ if Time.now - get_oidc_account_last_login_at(session_value) > max_age
255
+ # force user to re-login
256
+ clear_session
257
+ set_session_value(login_redirect_session_key, request.fullpath)
258
+ redirect require_login_redirect
259
+ end
260
+ end
261
+
262
+ if (claims = param_or_nil("claims"))
263
+ # The value is a JSON object listing the requested Claims.
264
+ claims = JSON.parse(claims)
265
+
266
+ claims.each do |_, individual_claims|
267
+ redirect_response_error("invalid_request") unless individual_claims.is_a?(Hash)
268
+
269
+ individual_claims.each do |_, claim|
270
+ redirect_response_error("invalid_request") unless claim.nil? || individual_claims.is_a?(Hash)
271
+ end
272
+ end
273
+ end
274
+
275
+ sc = scopes
276
+
277
+ if sc && sc.include?("offline_access")
278
+
279
+ sc.delete("offline_access")
280
+
281
+ # MUST ensure that the prompt parameter contains consent
282
+ # MUST ignore the offline_access request unless the Client
283
+ # is using a response_type value that would result in an
284
+ # Authorization Code
285
+ if param_or_nil("prompt") == "consent" && (
286
+ (response_type = param_or_nil("response_type")) && response_type.split(" ").include?("code")
287
+ )
288
+ request.params["access_type"] = "offline"
289
+ end
290
+
291
+ request.params["scope"] = sc.join(" ")
299
292
  end
300
293
 
301
294
  super
@@ -304,7 +297,7 @@ module Rodauth
304
297
  def require_authorizable_account
305
298
  try_prompt
306
299
  super
307
- try_acr_values
300
+ @acr = try_acr_values
308
301
  end
309
302
 
310
303
  def get_oidc_account_last_login_at(account_id)
@@ -348,22 +341,18 @@ module Rodauth
348
341
 
349
342
  case prompt
350
343
  when "none"
344
+ return unless request.get?
345
+
351
346
  redirect_response_error("login_required") unless logged_in?
352
347
 
353
348
  require_account
354
349
 
355
- if db[oauth_grants_table].where(
356
- oauth_grants_account_id_column => account_id,
357
- oauth_grants_oauth_application_id_column => oauth_application[oauth_applications_id_column],
358
- oauth_grants_redirect_uri_column => redirect_uri,
359
- oauth_grants_scopes_column => scopes.join(oauth_scope_separator),
360
- oauth_grants_access_type_column => "online"
361
- ).count.zero?
362
- redirect_response_error("consent_required")
363
- end
350
+ redirect_response_error("interaction_required") unless oidc_authorize_on_prompt_none?(account_from_session)
364
351
 
365
352
  request.env["REQUEST_METHOD"] = "POST"
366
353
  when "login"
354
+ return unless request.get?
355
+
367
356
  if logged_in? && request.cookies[oauth_prompt_login_cookie_key] == "login"
368
357
  ::Rack::Utils.delete_cookie_header!(response.headers, oauth_prompt_login_cookie_key, oauth_prompt_login_cookie_options)
369
358
  return
@@ -380,18 +369,17 @@ module Rodauth
380
369
 
381
370
  redirect require_login_redirect
382
371
  when "consent"
372
+ return unless request.post?
373
+
383
374
  require_account
384
375
 
385
- if db[oauth_grants_table].where(
386
- oauth_grants_account_id_column => account_id,
387
- oauth_grants_oauth_application_id_column => oauth_application[oauth_applications_id_column],
388
- oauth_grants_redirect_uri_column => redirect_uri,
389
- oauth_grants_scopes_column => scopes.join(oauth_scope_separator),
390
- oauth_grants_access_type_column => "online"
391
- ).count.zero?
392
- redirect_response_error("consent_required")
393
- end
376
+ sc = scopes || []
377
+
378
+ redirect_response_error("consent_required") if sc.empty?
379
+
394
380
  when "select-account"
381
+ return unless request.get?
382
+
395
383
  # only works if select_account plugin is available
396
384
  require_select_account if respond_to?(:require_select_account)
397
385
  else
@@ -403,44 +391,68 @@ module Rodauth
403
391
  return unless (acr_values = param_or_nil("acr_values"))
404
392
 
405
393
  acr_values.split(" ").each do |acr_value|
394
+ next unless oauth_acr_values_supported.include?(acr_value)
395
+
406
396
  case acr_value
407
- when "phr" then require_acr_value_phr
408
- when "phrh" then require_acr_value_phrh
397
+ when "phr"
398
+ return acr_value if require_acr_value_phr
399
+ when "phrh"
400
+ return acr_value if require_acr_value_phrh
409
401
  else
410
- require_acr_value(acr_value)
402
+ return acr_value if require_acr_value(acr_value)
411
403
  end
412
404
  end
405
+
406
+ nil
413
407
  end
414
408
 
415
409
  def require_acr_value_phr
416
- return unless respond_to?(:require_two_factor_authenticated)
410
+ return false unless respond_to?(:require_two_factor_authenticated)
417
411
 
418
412
  require_two_factor_authenticated
413
+ true
419
414
  end
420
415
 
421
416
  def require_acr_value_phrh
417
+ return false unless features.include?(:webauthn_login)
418
+
422
419
  require_acr_value_phr && two_factor_login_type_match?("webauthn")
423
420
  end
424
421
 
425
- def require_acr_value(_acr); end
422
+ def require_acr_value(_acr)
423
+ true
424
+ end
426
425
 
427
426
  def create_oauth_grant(create_params = {})
428
- if (nonce = param_or_nil("nonce"))
429
- create_params[oauth_grants_nonce_column] = nonce
430
- end
431
- if (acr = param_or_nil("acr"))
432
- create_params[oauth_grants_acr_column] = acr
433
- end
427
+ create_params.replace(oidc_grant_params.merge(create_params))
434
428
  super
435
429
  end
436
430
 
431
+ def create_oauth_grant_with_token(create_params = {})
432
+ create_params[oauth_grants_type_column] = "hybrid"
433
+ create_params[oauth_grants_account_id_column] = account_id
434
+ create_params[oauth_grants_expires_in_column] = Sequel.date_add(Sequel::CURRENT_TIMESTAMP, seconds: oauth_access_token_expires_in)
435
+ authorization_code = create_oauth_grant(create_params)
436
+ access_token = if oauth_jwt_access_tokens
437
+ _generate_jwt_access_token(create_params)
438
+ else
439
+ oauth_grant = valid_oauth_grant_ds.where(oauth_grants_code_column => authorization_code).first
440
+ _generate_access_token(oauth_grant)
441
+ end
442
+
443
+ {
444
+ "code" => authorization_code,
445
+ **json_access_token_payload(oauth_grants_token_column => access_token)
446
+ }
447
+ end
448
+
437
449
  def create_token(*)
438
450
  oauth_grant = super
439
451
  generate_id_token(oauth_grant)
440
452
  oauth_grant
441
453
  end
442
454
 
443
- def generate_id_token(oauth_grant)
455
+ def generate_id_token(oauth_grant, include_claims = false)
444
456
  oauth_scopes = oauth_grant[oauth_grants_scopes_column].split(oauth_scope_separator)
445
457
 
446
458
  return unless oauth_scopes.include?("openid")
@@ -461,7 +473,18 @@ module Rodauth
461
473
  # who just authorized its generation.
462
474
  return unless account
463
475
 
464
- fill_with_account_claims(id_token_claims, account, oauth_scopes)
476
+ if (claims = oauth_grant[oauth_grants_claims_column])
477
+ claims = JSON.parse(claims)
478
+ if (id_token_essential_claims = claims["id_token"])
479
+ oauth_scopes |= id_token_essential_claims.to_a
480
+
481
+ include_claims = true
482
+ end
483
+ end
484
+
485
+ # 5.4 - However, when no Access Token is issued (which is the case for the response_type value id_token),
486
+ # the resulting Claims are returned in the ID Token.
487
+ fill_with_account_claims(id_token_claims, account, oauth_scopes, param_or_nil("claims_locales")) if include_claims
465
488
 
466
489
  params = {
467
490
  jwks: oauth_application_jwks(oauth_application),
@@ -477,11 +500,31 @@ module Rodauth
477
500
  end
478
501
 
479
502
  # aka fill_with_standard_claims
480
- def fill_with_account_claims(claims, account, scopes)
503
+ def fill_with_account_claims(claims, account, scopes, claims_locales)
504
+ additional_claims_info = {}
505
+
481
506
  scopes_by_claim = scopes.each_with_object({}) do |scope, by_oidc|
482
507
  next if scope == "openid"
483
508
 
484
- oidc, param = scope.split(".", 2)
509
+ if scope.is_a?(Array)
510
+ # essential claims
511
+ param, additional_info = scope
512
+
513
+ param = param.to_sym
514
+
515
+ oidc, = OIDC_SCOPES_MAP.find do |_, oidc_scopes|
516
+ oidc_scopes.include?(param)
517
+ end || param.to_s
518
+
519
+ param = nil if oidc == param.to_s
520
+
521
+ additional_claims_info[param] = additional_info
522
+ else
523
+
524
+ oidc, param = scope.split(".", 2)
525
+
526
+ param = param.to_sym if param
527
+ end
485
528
 
486
529
  by_oidc[oidc] ||= []
487
530
 
@@ -490,13 +533,11 @@ module Rodauth
490
533
 
491
534
  oidc_scopes, additional_scopes = scopes_by_claim.keys.partition { |key| OIDC_SCOPES_MAP.key?(key) }
492
535
 
493
- if (claims_locales = param_or_nil("claims_locales"))
494
- claims_locales = claims_locales.split(" ").map(&:to_sym)
495
- end
536
+ claims_locales = claims_locales.split(" ").map(&:to_sym) if claims_locales
496
537
 
497
538
  unless oidc_scopes.empty?
498
539
  if respond_to?(:get_oidc_param)
499
- get_oidc_param = proxy_get_param(:get_oidc_param, claims, claims_locales)
540
+ get_oidc_param = proxy_get_param(:get_oidc_param, claims, claims_locales, additional_claims_info)
500
541
 
501
542
  oidc_scopes.each do |scope|
502
543
  scope_claims = claims
@@ -517,7 +558,7 @@ module Rodauth
517
558
  return if additional_scopes.empty?
518
559
 
519
560
  if respond_to?(:get_additional_param)
520
- get_additional_param = proxy_get_param(:get_additional_param, claims, claims_locales)
561
+ get_additional_param = proxy_get_param(:get_additional_param, claims, claims_locales, additional_claims_info)
521
562
 
522
563
  additional_scopes.each do |scope|
523
564
  get_additional_param[account, scope.to_sym]
@@ -527,23 +568,36 @@ module Rodauth
527
568
  end
528
569
  end
529
570
 
530
- def proxy_get_param(get_param_func, claims, claims_locales)
571
+ def proxy_get_param(get_param_func, claims, claims_locales, additional_claims_info)
531
572
  meth = method(get_param_func)
532
573
  if meth.arity == 2
533
- ->(account, param, cl = claims) { cl[param] = meth[account, param] }
574
+ lambda do |account, param, cl = claims|
575
+ additional_info = additional_claims_info[param] || EMPTY_HASH
576
+ value = additional_info["value"] || meth[account, param]
577
+ value = nil if additional_info["values"] && additional_info["values"].include?(value)
578
+ cl[param] = value if value
579
+ end
534
580
  elsif claims_locales.nil?
535
- ->(account, param, cl = claims) { cl[param] = meth[account, param, nil] }
581
+ lambda do |account, param, cl = claims|
582
+ additional_info = additional_claims_info[param] || EMPTY_HASH
583
+ value = additional_info["value"] || meth[account, param, nil]
584
+ value = nil if additional_info["values"] && additional_info["values"].include?(value)
585
+ cl[param] = value if value
586
+ end
536
587
  else
537
588
  lambda do |account, param, cl = claims|
538
589
  claims_values = claims_locales.map do |locale|
539
- meth[account, param, locale]
540
- end
590
+ additional_info = additional_claims_info[param] || EMPTY_HASH
591
+ value = additional_info["value"] || meth[account, param, locale]
592
+ value = nil if additional_info["values"] && additional_info["values"].include?(value)
593
+ value
594
+ end.compact
541
595
 
542
596
  if claims_values.uniq.size == 1
543
597
  cl[param] = claims_values.first
544
598
  else
545
599
  claims_locales.zip(claims_values).each do |locale, value|
546
- cl["#{param}##{locale}"] = value
600
+ cl["#{param}##{locale}"] = value if value
547
601
  end
548
602
  end
549
603
  end
@@ -580,23 +634,39 @@ module Rodauth
580
634
  end
581
635
 
582
636
  def do_authorize(response_params = {}, response_mode = param_or_nil("response_mode"))
583
- case param("response_type")
637
+ response_type = param("response_type")
638
+ case response_type
584
639
  when "id_token"
585
- response_params.replace(_do_authorize_id_token)
640
+ grant_params = oidc_grant_params
641
+ generate_id_token(grant_params, true)
642
+ response_params.replace("id_token" => grant_params[:id_token])
586
643
  when "code token"
587
644
  redirect_response_error("invalid_request") unless supports_token_response_type?
588
645
 
589
- response_params.replace(_do_authorize_code.merge(_do_authorize_token))
646
+ response_params.replace(create_oauth_grant_with_token)
590
647
  when "code id_token"
591
- response_params.replace(_do_authorize_code.merge(_do_authorize_id_token))
648
+ params = _do_authorize_code
649
+ oauth_grant = valid_oauth_grant_ds.where(oauth_grants_code_column => params["code"]).first
650
+ generate_id_token(oauth_grant)
651
+ response_params.replace(
652
+ "id_token" => oauth_grant[:id_token],
653
+ "code" => params["code"]
654
+ )
592
655
  when "id_token token"
593
656
  redirect_response_error("invalid_request") unless supports_token_response_type?
594
657
 
595
- response_params.replace(_do_authorize_id_token.merge(_do_authorize_token))
658
+ oauth_grant = _do_authorize_token(oauth_grants_type_column => "hybrid")
659
+ generate_id_token(oauth_grant)
660
+
661
+ response_params.replace(json_access_token_payload(oauth_grant))
596
662
  when "code id_token token"
597
663
  redirect_response_error("invalid_request") unless supports_token_response_type?
598
664
 
599
- response_params.replace(_do_authorize_code.merge(_do_authorize_id_token).merge(_do_authorize_token))
665
+ params = create_oauth_grant_with_token
666
+ oauth_grant = valid_oauth_grant_ds.where(oauth_grants_code_column => params["code"]).first
667
+ generate_id_token(oauth_grant)
668
+
669
+ response_params.replace(params.merge("id_token" => oauth_grant[:id_token]))
600
670
  when "none"
601
671
  response_mode ||= "none"
602
672
  end
@@ -605,23 +675,23 @@ module Rodauth
605
675
  super(response_params, response_mode)
606
676
  end
607
677
 
608
- def _do_authorize_id_token
678
+ def oidc_grant_params
609
679
  grant_params = {
610
680
  oauth_grants_account_id_column => account_id,
611
681
  oauth_grants_oauth_application_id_column => oauth_application[oauth_applications_id_column],
612
- oauth_grants_scopes_column => scopes.join(" ")
682
+ oauth_grants_scopes_column => scopes.join(oauth_scope_separator)
613
683
  }
614
684
  if (nonce = param_or_nil("nonce"))
615
685
  grant_params[oauth_grants_nonce_column] = nonce
616
686
  end
617
- if (acr = param_or_nil("acr"))
618
- grant_params[oauth_grants_acr_column] = acr
687
+ grant_params[oauth_grants_acr_column] = @acr if @acr
688
+ if (claims_locales = param_or_nil("claims_locales"))
689
+ grant_params[oauth_grants_claims_locales_column] = claims_locales
690
+ end
691
+ if (claims = param_or_nil("claims"))
692
+ grant_params[oauth_grants_claims_column] = claims
619
693
  end
620
- oauth_grant = generate_token(grant_params, false)
621
- generate_id_token(oauth_grant)
622
- params = json_access_token_payload(oauth_grant)
623
- params.delete("access_token")
624
- params
694
+ grant_params
625
695
  end
626
696
 
627
697
  def authorize_response(params, mode)
@@ -630,18 +700,6 @@ module Rodauth
630
700
  super
631
701
  end
632
702
 
633
- # Logout
634
-
635
- def validate_oidc_logout_params
636
- redirect_response_error("invalid_request") unless param_or_nil("id_token_hint")
637
- # check if valid token hint type
638
- return unless (redirect_uri = param_or_nil("post_logout_redirect_uri"))
639
-
640
- return if check_valid_uri?(redirect_uri)
641
-
642
- redirect_response_error("invalid_request")
643
- end
644
-
645
703
  # Webfinger
646
704
 
647
705
  def json_webfinger_payload
@@ -673,25 +731,15 @@ module Rodauth
673
731
 
674
732
  scope_claims.unshift("auth_time")
675
733
 
676
- response_types_supported = metadata[:response_types_supported]
677
-
678
- response_types_supported |= %w[none]
679
- response_types_supported |= ["code id_token"] if metadata[:grant_types_supported].include?("authorization_code")
680
- if metadata[:grant_types_supported].include?("implicit")
681
- response_types_supported |= ["code token", "id_token token", "code id_token token"]
682
- end
683
-
684
- alg_values, enc_values = oauth_jwt_jwe_keys.keys.transpose
685
-
686
734
  metadata.merge(
687
735
  userinfo_endpoint: userinfo_url,
688
- end_session_endpoint: (oidc_logout_url if use_rp_initiated_logout?),
689
- response_types_supported: response_types_supported,
690
736
  subject_types_supported: %w[public pairwise],
737
+ acr_values_supported: oauth_acr_values_supported,
738
+ claims_parameter_supported: true,
691
739
 
692
- id_token_signing_alg_values_supported: metadata[:token_endpoint_auth_signing_alg_values_supported],
693
- id_token_encryption_alg_values_supported: Array(alg_values),
694
- id_token_encryption_enc_values_supported: Array(enc_values),
740
+ id_token_signing_alg_values_supported: oauth_jwt_jws_algorithms_supported,
741
+ id_token_encryption_alg_values_supported: oauth_jwt_jwe_algorithms_supported,
742
+ id_token_encryption_enc_values_supported: oauth_jwt_jwe_encryption_methods_supported,
695
743
 
696
744
  userinfo_signing_alg_values_supported: oauth_jwt_jws_algorithms_supported,
697
745
  userinfo_encryption_alg_values_supported: oauth_jwt_jwe_algorithms_supported,