Sake.Auth.Authorize (Sake v0.4.3)

Copy Markdown View Source

The authorization endpoint: GET validates the request and shows the consent page (or redirects at once when consent is remembered); POST records the decision. Mount it inside the pipeline that requires a signed-in person; Sake reads the person through Sake.Auth.Subject.

After it resolves the resource (the endpoint URL the token is for), it asks the subject module's optional authorize_resource?/2 whether this person may authorize a client for it; a false answer sends the client access_denied. A remembered consent is kept per person, client and resource.

The consent form is protected in two layers. The hidden request field is a signed blob bound to the signed-in person, and it expires after ten minutes: a form posted by anyone else, or later, is refused. When the host's pipeline runs Plug.CSRFProtection (protect_from_forgery in Phoenix), the form also carries the CSRF token and the host's plug checks it. A Plug-only host without CSRF middleware sends an empty _csrf_token field and relies on the signed blob alone.

The consent and error pages refuse to be framed (x-frame-options: DENY and content-security-policy: frame-ancestors 'none').

With par: (RFC 9126), a request with a request_uri is the pushed request it names, taken once: its client_id must be the client that pushed it, and every other parameter of the query is ignored. A request_uri that is unknown, expired, already used or another client's gets an error page. When pushed requests are required (par: [required: true], or a client registered with require_pushed_authorization_requests), any other request is sent back with invalid_request. The consent form carries the request itself, so approving or denying needs the request_uri no more; a reload of the page after it was taken shows the error page.

A request may say how the person must have signed in (RFC 9470): acr_values (space-separated, any one will do) and max_age (in seconds), sent directly or pushed. Before anything is decided, the subject module's authentication/1 says how the signed-in person did; when that does not meet the request, its reauthenticate/2 sends them to sign in again and back to this URL (a pushed request is kept for the return, until it expires), or, without it, an error page says so. The code carries the acr and auth_time of the approval into the tokens. See Sake.Auth.Subject.

Summary

Functions

Issues a code for request (a map with client_id, redirect_uri, code_challenge, scopes, resource) and subject_id; returns the plain code. authentication, %{acr: acr, auth_time: datetime}, is how the person signed in, which the code's tokens carry (RFC 9470).

Functions

issue_code(config, request, subject_id, authentication \\ %{})

@spec issue_code(Sake.Auth.Config.t(), map(), String.t(), map()) :: String.t()

Issues a code for request (a map with client_id, redirect_uri, code_challenge, scopes, resource) and subject_id; returns the plain code. authentication, %{acr: acr, auth_time: datetime}, is how the person signed in, which the code's tokens carry (RFC 9470).