OpenID conformance test: we get a warning for not having a value for every claim. But we can explictly list support claims. Nothing we can do about a warning in the complience.

This commit is contained in:
Dan Milne
2026-01-02 16:35:12 +11:00
parent 182682024d
commit 9589d8cce3
3 changed files with 21 additions and 46 deletions

View File

@@ -30,7 +30,17 @@ class OidcController < ApplicationController
id_token_signing_alg_values_supported: ["RS256"], id_token_signing_alg_values_supported: ["RS256"],
scopes_supported: ["openid", "profile", "email", "groups", "offline_access"], scopes_supported: ["openid", "profile", "email", "groups", "offline_access"],
token_endpoint_auth_methods_supported: ["client_secret_post", "client_secret_basic"], token_endpoint_auth_methods_supported: ["client_secret_post", "client_secret_basic"],
claims_supported: ["sub", "email", "email_verified", "name", "preferred_username", "groups", "admin", "auth_time", "acr", "azp", "at_hash"], claims_supported: [
"sub", # Always included
"email", # email scope
"email_verified", # email scope
"name", # profile scope
"preferred_username", # profile scope
"updated_at", # profile scope
"groups" # groups scope
# Note: Custom claims are also supported but not listed here
# ID-token-only claims (auth_time, acr, azp, at_hash, nonce) are not listed
],
code_challenge_methods_supported: ["plain", "S256"], code_challenge_methods_supported: ["plain", "S256"],
backchannel_logout_supported: true, backchannel_logout_supported: true,
backchannel_logout_session_supported: true backchannel_logout_session_supported: true
@@ -657,26 +667,13 @@ class OidcController < ApplicationController
end end
# Profile claims (only if 'profile' scope requested) # Profile claims (only if 'profile' scope requested)
# Per OIDC Core spec section 5.4, all profile claims SHOULD be returned # Per OIDC Core spec section 5.4, include available profile claims
# Only include claims we have data for - omit unknown claims rather than returning null
if requested_scopes.include?("profile") if requested_scopes.include?("profile")
# Use username if available, otherwise email as preferred_username # Use username if available, otherwise email as preferred_username
claims[:preferred_username] = user.username.presence || user.email_address claims[:preferred_username] = user.username.presence || user.email_address
# Name: use stored name or fall back to email # Name: use stored name or fall back to email
claims[:name] = user.name.presence || user.email_address claims[:name] = user.name.presence || user.email_address
# Standard profile claims we don't store - set to nil (optional per spec)
claims[:given_name] = nil
claims[:family_name] = nil
claims[:middle_name] = nil
claims[:nickname] = nil
claims[:profile] = nil
claims[:picture] = nil
claims[:website] = nil
claims[:gender] = nil
claims[:birthdate] = nil
claims[:zoneinfo] = nil
claims[:locale] = nil
# Time the user's information was last updated # Time the user's information was last updated
claims[:updated_at] = user.updated_at.to_i claims[:updated_at] = user.updated_at.to_i
end end

View File

@@ -23,17 +23,10 @@ class OidcJwtService
iat: now iat: now
} }
# Email claims (only if 'email' scope requested) # NOTE: Email and profile claims are NOT included in the ID token for authorization code flow
if requested_scopes.include?("email") # Per OIDC Core spec §5.4, these claims should only be returned via the UserInfo endpoint
payload[:email] = user.email_address # For implicit flow (response_type=id_token), claims would be included here, but we only
payload[:email_verified] = true # support authorization code flow, so these claims are omitted from the ID token.
end
# Profile claims (only if 'profile' scope requested)
if requested_scopes.include?("profile")
payload[:preferred_username] = user.username.presence || user.email_address
payload[:name] = user.name.presence || user.email_address
end
# Add nonce if provided (OIDC requires this for implicit flow) # Add nonce if provided (OIDC requires this for implicit flow)
payload[:nonce] = nonce if nonce.present? payload[:nonce] = nonce if nonce.present?

View File

@@ -115,25 +115,10 @@ class OidcUserinfoControllerTest < ActionDispatch::IntegrationTest
# Required claims # Required claims
assert json["sub"].present? assert json["sub"].present?
# All standard profile claims should be present (per OIDC Core spec section 5.4) # Profile claims we support should be present
# Some may be null if we don't have the data, but the keys should exist assert json["name"].present?, "Should include name with profile scope"
assert json.key?("name"), "Should include name claim" assert json["preferred_username"].present?, "Should include preferred_username with profile scope"
assert json.key?("given_name"), "Should include given_name claim (may be null)" assert json["updated_at"].present?, "Should include updated_at with profile scope"
assert json.key?("family_name"), "Should include family_name claim (may be null)"
assert json.key?("middle_name"), "Should include middle_name claim (may be null)"
assert json.key?("nickname"), "Should include nickname claim (may be null)"
assert json.key?("preferred_username"), "Should include preferred_username claim"
assert json.key?("profile"), "Should include profile claim (may be null)"
assert json.key?("picture"), "Should include picture claim (may be null)"
assert json.key?("website"), "Should include website claim (may be null)"
assert json.key?("gender"), "Should include gender claim (may be null)"
assert json.key?("birthdate"), "Should include birthdate claim (may be null)"
assert json.key?("zoneinfo"), "Should include zoneinfo claim (may be null)"
assert json.key?("locale"), "Should include locale claim (may be null)"
assert json.key?("updated_at"), "Should include updated_at claim"
# Verify preferred_username is using username or email
assert json["preferred_username"].present?, "preferred_username should have a value"
# Email claims should NOT be present # Email claims should NOT be present
assert_nil json["email"], "Should not include email without email scope" assert_nil json["email"], "Should not include email without email scope"