@@ -3,26 +3,38 @@ class OidcJwtService
33
44 class << self
55 # Generate an ID token (JWT) for the user
6- def generate_id_token ( user , application , consent : nil , nonce : nil , access_token : nil , auth_time : nil , acr : nil )
6+ def generate_id_token ( user , application , consent : nil , nonce : nil , access_token : nil , auth_time : nil , acr : nil , scopes : "openid" )
77 now = Time . current . to_i
88 # Use application's configured ID token TTL (defaults to 1 hour)
99 ttl = application . id_token_expiry_seconds
1010
1111 # Use pairwise SID from consent if available, fallback to user ID
1212 subject = consent &.sid || user . id . to_s
1313
14+ # Parse scopes (space-separated string)
15+ requested_scopes = scopes . to_s . split
16+
17+ # Required claims (always included per OIDC Core spec)
1418 payload = {
1519 iss : issuer_url ,
1620 sub : subject ,
1721 aud : application . client_id ,
1822 exp : now + ttl ,
19- iat : now ,
20- email : user . email_address ,
21- email_verified : true ,
22- preferred_username : user . username . presence || user . email_address ,
23- name : user . name . presence || user . email_address
23+ iat : now
2424 }
2525
26+ # Email claims (only if 'email' scope requested)
27+ if requested_scopes . include? ( "email" )
28+ payload [ :email ] = user . email_address
29+ payload [ :email_verified ] = true
30+ end
31+
32+ # Profile claims (only if 'profile' scope requested)
33+ if requested_scopes . include? ( "profile" )
34+ payload [ :preferred_username ] = user . username . presence || user . email_address
35+ payload [ :name ] = user . name . presence || user . email_address
36+ end
37+
2638 # Add nonce if provided (OIDC requires this for implicit flow)
2739 payload [ :nonce ] = nonce if nonce . present?
2840
@@ -44,12 +56,13 @@ def generate_id_token(user, application, consent: nil, nonce: nil, access_token:
4456 payload [ :at_hash ] = at_hash
4557 end
4658
47- # Add groups if user has any
48- if user . groups . any?
59+ # Groups claims (only if 'groups' scope requested)
60+ if requested_scopes . include? ( "groups" ) && user . groups . any?
4961 payload [ :groups ] = user . groups . pluck ( :name )
5062 end
5163
5264 # Merge custom claims from groups (arrays are combined, not overwritten)
65+ # Note: Custom claims from groups are always merged (not scope-dependent)
5366 user . groups . each do |group |
5467 payload = deep_merge_claims ( payload , group . parsed_custom_claims )
5568 end
0 commit comments