OAuth 2.0 / OpenID Connect authorization endpoint (RFC 6749 §3.1, OIDC Core §3.1.2).
Handles GET /oauth/authorize, the front-channel browser flow that ends in
an authorization code (RFC 6749 §4.1). This module owns only the HTTP and
protocol-framing concerns: it parses and validates the request through
Attesto.AuthorizationRequest, classifies failures by where they may be
reported (OIDC Core §3.1.2.6), and on success mints a single-use code through
Attesto.AuthorizationCode.issue/3 and redirects back to the client. Every
identity decision - who the resource owner is, and whether they consent - is
delegated to host callbacks on AttestoPhoenix.Config. No login or consent
UI lives here.
Error disposition (OIDC Core §3.1.2.6, RFC 6749 §4.1.2.1)
The client_id and redirect_uri are validated BEFORE anything is rendered
or redirected. A request whose client_id is unknown, or whose
redirect_uri does not exactly match the client's registered set, is
untrusted: the server MUST NOT redirect back to the supplied URI (that would
be an open redirect), so it renders a direct error page to the user agent.
Only once the client_id/redirect_uri pair is established as trusted is any
further error (bad response_type, scope, PKCE, max_age) reported by
redirecting back to the validated redirect_uri with an error (and
error_description/state) query parameter. Attesto.AuthorizationRequest
performs this classification; this controller turns each class into the
correct HTTP response.
PKCE is mandatory (RFC 7636)
Attesto.AuthorizationRequest requires a valid S256 code_challenge; there
is no PKCE-less path. The challenge is carried into the issued code so the
token endpoint can verify the matching verifier on redemption.
Resource-owner authentication and consent (host policy)
Authenticating the end user and obtaining consent are host policy, not
protocol, so they are delegated to two AttestoPhoenix.Config callbacks:
:authenticate_resource_owner-(conn, request, auth_opts -> {:authenticated, subject} | {:halt, conn} | {:none} | {:error, :login_required | :consent_required | :interaction_required}). Returns{:authenticated, subject}once a resource owner is established for this request,{:halt, conn}to take over the connection (e.g. redirect to a login page that, after login, re-enters this endpoint with the same authorization parameters),{:none}when no subject can be established without UI, or an{:error, _}to explicitly classify why interaction is required (OIDC Core §3.1.2.6). Thesubjectis a map carrying at least:subject(the subject identifier, OIDC Core §2sub) and optionally:auth_time,:acr, and:amr(OIDC Core §2), threaded into the code's claims so the token endpoint can mint the ID token.auth_optsis a map carrying the OIDC Core §3.1.2.1 authentication directives the host MUST honour::prompt(the parsedpromptlist),:force_reauth(trueforprompt=login: reauthenticate even if a session exists, returning a freshauth_time),:interactive(falseforprompt=none: the host MUST NOT render any UI, returning{:authenticated, subject}only if it can be established silently, else{:none}), and:max_age(when present, the host MUST reauthenticate if the existing authentication is older and return the resultingauth_time). Underprompt=nonethe controller converts a{:halt, conn}or{:none}into alogin_requiredredirect rather than letting any UI run; a{:halt, conn}consent screen becomesconsent_required(OIDC Core §3.1.2.6).:consent-(conn, request, subject -> {:consented, subject} | {:halt, conn} | {:denied, reason}). Returns{:consented, subject}once the resource owner has authorized the request (the returnedsubjectmay carry consent-derived claims),{:halt, conn}to take over the connection (e.g. render a consent screen that re-enters this endpoint), or{:denied, _reason}to refuse, which is reported back to the client as the RFC 6749 §4.1.2.1access_deniederror by redirect. When the host does not supply:consent, consent is treated as implicitly granted for the authenticated subject.
Both callbacks may hand control back to a host-rendered page; the controller only proceeds to mint a code when both yield a subject. The actual login and consent UI lives in the host application, never in this library.
Configuration contract
All host policy is resolved through AttestoPhoenix.Config; nothing is
hardcoded here. This controller reads (see AttestoPhoenix.Config for the
authoritative definitions and defaults):
:load_client- client lookup and revocation gate (RFC 6749 §2.2). An unknown or revoked client is a direct (non-redirectable) error.:client_redirect_uris-(client -> [String.t()])the client's registered redirect URIs, the trusted set the requestredirect_uriis exact-matched against (RFC 6749 §3.1.2.3).:client_id-(client -> String.t())the client's identifier, carried into the issued code.:authenticate_resource_owner,:consent- the host login/consent hooks described above.:code_store- theAttesto.CodeStorebacking the issued code.:authorization_code_ttl- the code lifetime, seconds.:on_event- the optional audit/telemetry hook (viaAttestoPhoenix.Event).
Summary
Functions
Authorization endpoint action (RFC 6749 §3.1, OIDC Core §3.1.2).
Functions
@spec authorize(Plug.Conn.t(), map()) :: Plug.Conn.t()
Authorization endpoint action (RFC 6749 §3.1, OIDC Core §3.1.2).
Validates the request, authenticates and obtains consent from the resource
owner via host callbacks, issues a single-use authorization code, and
302-redirects back to the client's redirect_uri with code (and state,
when present). Failures are dispatched to a direct error page or a redirected
error per the classification in the moduledoc.