Docs
  • 0.1.0latest

Authorization

The authorization endpoint's fixed order of checks, pushed authorization requests, prompt and max_age, the two-factor policy and consent as a record.

GET|POST <issuer>/oauth2/authorize

The authorization endpoint (RFC 6749 §4.1.1) judges a request in a fixed order. Until the client is known and the redirect URI is one it registered, a refusal is shown on a page at the server and sent nowhere, so a URI written into a forged request never receives an answer. Every later refusal goes back to the registered URI with error, state and iss (RFC 9207).

A request needs PKCE with S256. A valid request is kept for ten minutes and the browser is sent to <issuer>/login carrying only the kept request's id. The pending request belongs to the browser that brought it, by the cookie __Host-tessari-browser: another browser holding the request's id cannot sign in for it, answer its consent or receive its code.

Once the user has signed in, the browser continues at <issuer>/oauth2/authorize/resume. When the user's consent to the client covers every scope and resource asked for, the request is answered once at its redirect URI with a code, its state and iss; otherwise the browser is sent to <issuer>/consent.

prompt and max_age

  • prompt=login asks for a new sign-in whatever the session.
  • max_age in seconds asks for a sign-in no older than that.
  • prompt=none asks for no page. Without a session cookie it is refused with login_required. With one it is answered from the session with a code, or at its redirect URI with login_required (no live session, or one older than max_age), consent_required or interaction_required. Each refusal is recorded.

The company's two-factor policy

Each company has a two-factor policy, optional until an operator sets it. Where it is required and the account holds no second factor, no code is issued: the browser is sent to <issuer>/account to add one, and the request waits until then. A prompt=none request gets interaction_required.

Pushed authorization requests

A client may push the parameters to POST <issuer>/oauth2/par (RFC 9126), authenticating exactly as at the token endpoint. They are judged as the authorization endpoint judges them, every refusal is answered to the client, and the answer names them by a request_uri valid for sixty seconds. The browser then brings only client_id and that request_uri to the authorization endpoint, where the pushed request is claimed once, by the client that pushed it, and nothing else in the URL is read. Pushing is advertised in the metadata and not required.

The consent page reads GET <issuer>/login/api/consent?interaction=<id>, which lists only the scopes and resources not granted yet, and posts the user's allow or deny. Allowing records the grant before a code exists; denying grants nothing and answers access_denied.

Consent is a record per user and client holding the granted scopes, resources and the consent policy version. A request outside it is asked for exactly what is missing; simultaneous grants are all kept; a revocation records who made it. When the policy version rises, because a release starts releasing something new under a scope, every earlier grant is asked for once more. The admin console's own client is always shown the consent page, since what it grants is administrative authority.

Users see and withdraw their grants in the account portal.