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

Sign up to get free protection for your applications and to get access to all the features.
@@ -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,