diff --git a/app/controllers/oidc_controller.rb b/app/controllers/oidc_controller.rb index 29144db..cbea16c 100644 --- a/app/controllers/oidc_controller.rb +++ b/app/controllers/oidc_controller.rb @@ -657,9 +657,28 @@ class OidcController < ApplicationController end # Profile claims (only if 'profile' scope requested) + # Per OIDC Core spec section 5.4, all profile claims SHOULD be returned if requested_scopes.include?("profile") - claims[:preferred_username] = user.email_address + # Use username if available, otherwise email as preferred_username + claims[:preferred_username] = user.username.presence || user.email_address + # Name: use stored name or fall back to email 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 + claims[:updated_at] = user.updated_at.to_i end # Groups claim (only if 'groups' scope requested) diff --git a/test/controllers/oidc_userinfo_controller_test.rb b/test/controllers/oidc_userinfo_controller_test.rb index f749b5f..b7c4b4a 100644 --- a/test/controllers/oidc_userinfo_controller_test.rb +++ b/test/controllers/oidc_userinfo_controller_test.rb @@ -115,9 +115,25 @@ class OidcUserinfoControllerTest < ActionDispatch::IntegrationTest # Required claims assert json["sub"].present? - # Profile claims should be present - assert_equal @user.email_address, json["preferred_username"], "Should include preferred_username with profile scope" - assert json["name"].present?, "Should include name with profile scope" + # All standard profile claims should be present (per OIDC Core spec section 5.4) + # Some may be null if we don't have the data, but the keys should exist + assert json.key?("name"), "Should include name claim" + assert json.key?("given_name"), "Should include given_name claim (may be null)" + 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 assert_nil json["email"], "Should not include email without email scope"