OpenID Connect UserInfo endpoint (OpenID Connect Core 1.0 §5.3).
Returns claims about the authenticated subject as a JSON object. The endpoint is a protected resource: the caller presents the access token issued during authentication, and the endpoint releases the subject claims the token's scopes authorize.
Authentication
Verification is delegated to the engine's protected-resource verify path,
Attesto.Plug.Authenticate, which this controller runs at the top of its
action. That plug parses the Authorization header (Bearer, RFC 6750 §2.1,
or DPoP, RFC 9449 §7.1), verifies the access token through Attesto.Token,
and - for a sender-constrained token - enforces the DPoP / mTLS binding,
honouring cnf.jkt / cnf.x5t#S256. A DPoP-bound token presented under the
Bearer scheme is rejected there, not here. On failure the plug halts the conn
with the RFC 6750 §3 / RFC 9449 §7.1 WWW-Authenticate challenge, which this
controller returns unchanged.
Per OpenID Connect Core §5.3.1 both GET and POST are accepted; the host
router maps both verbs to the :userinfo action.
Authorization
The verified access token MUST carry the openid scope (OpenID Connect Core
§5.3.1). A token without it is answered 403 with error="insufficient_scope"
and the scope="openid" auth-param (RFC 6750 §3.1).
Claims
The scopes on the access token (its scope claim, RFC 9068 §2.2.3) gate which
claims are released (OpenID Connect Core §5.4):
profile- the OpenID Connect Core §5.4 profile claim set.email-emailandemail_verified.address- theaddressclaim (a JSON object, OpenID Connect Core §5.1.1).phone-phone_numberandphone_number_verified.
The host supplies the claim values through the :build_userinfo_claims
callback (see AttestoPhoenix.Config); this controller keeps only the values
the granted scopes authorize and always includes sub (OpenID Connect Core
§5.3.2), the stable subject identifier, regardless of scope.
Beyond the scope-implied set, individual claims requested through the OpenID
Connect claims request parameter's userinfo member (OpenID Connect Core
§5.5) are also released. The authorization endpoint records that parameter on
the access token (its claims claim) at issuance; the verify path surfaces it
here, and the named claims are added to the release allow-list so a Relying
Party can obtain a single claim without requesting the whole scope. A claim
the host's source does not supply is simply omitted (a UserInfo response need
not contain every requested claim, OpenID Connect Core §5.5). When the
provider advertises claims_parameter_supported: false (the default, see
AttestoPhoenix.Config), the access token carries no claims claim and this
reduces to scope-gated release.
Configuration contract
Resolved through AttestoPhoenix.Config (see that module for the
authoritative definitions):
:build_userinfo_claims- the host's claim source (required to mount this endpoint).:issuer,:audience,:keystore,:access_token_ttl- claim-level policy supplied to the engine verify path as anAttesto.Config.:dpop_enabled,:dpop_nonce_required,:nonce_store,:replay_check,:cert_der,:mtls_enabled,:htu- sender-constraint policy and stores, threaded intoAttesto.Plug.Authenticate.
Summary
Functions
UserInfo action (OpenID Connect Core §5.3). Handles both GET and POST
(OpenID Connect Core §5.3.1).
Functions
@spec userinfo(Plug.Conn.t(), map()) :: Plug.Conn.t()
UserInfo action (OpenID Connect Core §5.3). Handles both GET and POST
(OpenID Connect Core §5.3.1).
Named userinfo rather than call so it does not collide with the
Phoenix.Controller plug entrypoint (Phoenix.Controller.Pipeline.call/2)
that dispatches the action.