Skip to content
Kenta Ishizaki edited this page Jun 15, 2026 · 1 revision

Claims

Claims can be defined in a claims block inside config/initializers/doorkeeper_openid_connect.rb:

Doorkeeper::OpenidConnect.configure do
  claims do
    claim :email do |resource_owner|
      resource_owner.email
    end

    claim :full_name do |resource_owner|
      "#{resource_owner.first_name} #{resource_owner.last_name}"
    end

    claim :preferred_username, scope: :openid do |resource_owner, scopes, access_token|
      # Pass the resource_owner's preferred_username if the application has
      # `profile` scope access. Otherwise, provide a more generic alternative.
      scopes.exists?(:profile) ? resource_owner.preferred_username : "summer-sun-9449"
    end

    claim :groups, response: [:id_token, :user_info] do |resource_owner|
      resource_owner.groups
    end
  end
end

Each claim block will be passed:

  • the resource_owner, which is the return value of resource_owner_authenticator in your initializer
  • the scopes granted by the access token, which is an instance of Doorkeeper::OAuth::Scopes
  • the access_token itself, which is an instance of Doorkeeper::AccessToken

By default all custom claims are only returned from the UserInfo endpoint and not included in the ID token. You can optionally pass a response: keyword with one or both of the symbols :id_token or :user_info to specify where the claim should be returned.

You can also pass a scope: keyword argument on each claim to specify which OAuth scope should be required to access the claim. If you define any of the defined Standard Claims they will by default use their corresponding scopes (profile, email, address and phone), and any other claims will by default use the profile scope. Again, to use any of these scopes you need to enable them as described above.

You can also pass an array of scopes, in which case the claim is returned whenever the access token grants any of the listed scopes. This is useful when you want to expose the same claim under both a standard scope and an aggregate scope:

claim :given_name, scope: [:profile, :all_data] do |user|
  user.first_name
end

claim :email, scope: [:email, :all_data] do |user|
  user.email
end

Authentication Context (acr) and Methods (amr)

The claim DSL also handles standard top-level ID Token claims such as acr (Authentication Context Class Reference) and amr (Authentication Methods References) — commonly used to expose MFA status to clients:

claims do
  claim :acr, response: [:id_token, :user_info], scope: :openid do |resource_owner|
    # Single string — e.g. a URI like "urn:mace:incommon:iap:silver",
    # or a numeric Level of Assurance "1".."4" per ISO/IEC 29115.
    resource_owner.mfa_enabled? ? "2" : "1"
  end

  claim :amr, response: [:id_token, :user_info], scope: :openid do |resource_owner|
    # Array of strings, per RFC 8176.
    methods = ["pwd"]
    methods << "mfa" if resource_owner.mfa_enabled?
    methods << "otp" if resource_owner.last_login_used_totp?
    methods
  end
end

Two defaults are worth calling out because they bite silently:

  • response: [:id_token, :user_info] — custom claims default to UserInfo only, but relying parties usually expect acr / amr on the ID Token.
  • scope: :openid — without it, non-standard claims fall back to the profile scope and disappear for clients that only requested openid.

Claim names you declare here are automatically advertised under claims_supported in the discovery document. The list of advertised acr values (acr_values_supported) is not currently generated.

Clone this wiki locally