captured core.authorization

Authorize a client for the signed-in user

The authorization endpoint of OAuth 2.1, GET or POST (OpenID Connect Core §3.1.2.1). It checks the client, its redirect URI against the registration and the environment, its grant and response type and the dpop_jkt it names, before anything about the user. Then it reads the browser session. Without one, or for a request whose sign-in is too old for what it asks (prompt=login, max_age, a dangerous scope, a native_backend client), the person signs in; under prompt=none the client gets login_required instead. With a session it refuses an agent scope above the client's cap and a QAuth API audience the client does not list, and asks for consent when no stored or administrative consent covers the request (consent_required under prompt=none). Otherwise it mints the code, under the consent and the session, both read again in its transaction, and sends it back with iss. With INTERACTION_UI_ENABLED on, the sign-in and the consent are interactions: the endpoint redirects to the ceremony page with the interaction id and nothing else, and when the interaction finishes the request is decided again for the session it holds, and the code minted, or the next interaction started.

What this view shows

GET and POST /oauth/authorize from the request to the response, in both modes, and the answer of the Interaction API that finishes or cancels one of its interactions.

Open world: what is not drawn here is not ruled out. Only the guarantees below are binding.

Left out of this view:

The main story

When: INTERACTION_UI_ENABLED is on: the sign-in and the consent are interactions (#628), the host is the primary host of an enabled realm, the address is under its limit, the parameters pass the route schema, and the client, its redirect URI, its grant and response type and dpop_jkt all pass, an operator provisioned the client (provisioned_by_operator): the system client or the seed manifest, the request carries no session cookie, or one that names a cookie key this process has not read yet and may not read again yet (#493), which is left for the next request, nothing in the request is refused after the session, it carries no prompt, or prompt=login, prompt=consent or prompt=create, the request carries no prompt=create, nothing asks for a fresh sign-in, or the sign-in is fresh enough for what asks, a stored consent covers every requested scope at each requested resource, or the client's administrative consent does (ADR-017 Decision 9), and nothing asks for the screen, the client and its redirect URI still pass when the interaction finishes or is cancelled, the session the interaction holds is live and its account may use it, when the request is decided again.

  1. Wait for an authorization request: GET /oauth/authorize arrives with its parameters in the query, or POST with them in a form
  2. Find the realm of the host: the request has its realm
  3. Count the request against the authorize limit: the address is under its limit
  4. Check the parameters against the authorize schema: the parameters match the schema
  5. Find the client: the client is found
  6. Check the redirect URI against the client's registration: redirect_uri is registered
  7. Check the redirect URI against the environment policy: the environment permits the redirect URI
  8. Check that the client may use the endpoint: the client may use the endpoint
  9. Read the DPoP key the code is to be bound to: dpop_jkt is absent, unread or well formed
  10. Check a request for a registration: the request carries no prompt=create
  11. Find the browser session: no usable session: the person signs in first, and the request is decided again with that session
  12. Send the person to sign in: INTERACTION_UI_ENABLED is on
  13. Start a sign-in interaction: the interaction is stored
  14. The person signs in at the ceremony page: the person's last answer, such as the right password, finishes the interaction
  15. End the interaction before anything is issued: the interaction is over
  16. Check the request again, as the endpoint checks it: the request still passes
  17. Find the session the interaction holds: the session is live: the request is decided again for it
  18. Refuse an agent scope above the client's cap: no agent scope is above the cap; the scopes are the requested ones the client's allowlist holds
  19. Refuse a QAuth API audience the client does not list: every QAuth API audience among the resources is one the client lists
  20. Read the consent, and decide whether the sign-in is fresh enough and the consent covers the request: the sign-in is fresh enough and a consent covers the request
  21. Mint the authorization code under the consent and the session: the code is stored, for the request whose interaction finished

Result: Send the authorization code to the client once the interaction finished.

The flow

GET /oauth/authorize arrives with its parameters in the query, or POST with them in a form an answer, a cancel or a read names an interaction of this request that already finished, such as a replayed or a second form post the host names no enabled realm with an issuer, or is one of its endpoint hosts the request has its realm the address has used up its requests the address is under its limit the parameters do not match the schema the parameters match the schema the client_id names no client of the realm the client is found redirect_uri is not registered for the client redirect_uri is registered no environment permits that redirect_uri the environment permits the redirect URI the client is disabled or suspended the client is not registered for the authorization_code grant the client is not registered for the code response type the client may use the endpoint dpop_jkt is not one thumbprint, for a client an operator provisioned dpop_jkt is not one thumbprint, for a client no operator provisioned dpop_jkt is absent, unread or well formed the request carries no prompt=create prompt=create without openid, for a client an operator provisioned prompt=create without openid, for a client no operator provisioned the realm offers no sign-up, for a client an operator provisioned the realm offers no sign-up, for a client no operator provisioned the client may not register accounts, for a client an operator provisioned the client may not register accounts, for a client no operator provisioned prompt=create with max_age, for a client an operator provisioned prompt=create with max_age, for a client no operator provisioned the session cookie cannot be decoded the registration is allowed the interaction is stored the new password creates the account, which finishes the interaction the person cancels, with the CSRF value of the step they see; the interaction ends the session cookie cannot be decoded no usable session under prompt=none, for a client an operator provisioned; step_up.required is recorded no usable session under prompt=none, for a client no operator provisioned no usable session: the person signs in first, and the request is decided again with that session the session is live an agent scope is above the cap, decided when the interaction finished an agent scope is above the cap, for a client an operator provisioned an agent scope is above the cap, for a client no operator provisioned no agent scope is above the cap; the scopes are the requested ones the client's allowlist holds a resource names a QAuth API audience the client does not list, decided when the interaction finished a resource names a QAuth API audience the client does not list, for a client an operator provisioned a resource names a QAuth API audience the client does not list, for a client no operator provisioned every QAuth API audience among the resources is one the client lists prompt=none, and the sign-in is too old for what is asked, for a client an operator provisioned prompt=none, and the sign-in is too old for what is asked, for a client no operator provisioned prompt=none, and no consent covers the request, for a client an operator provisioned prompt=none, and no consent covers the request, for a client no operator provisioned the sign-in is too old for what is asked: the person signs in again no consent covers the request: the person is asked the sign-in is fresh enough and a consent covers the request the code is stored, for the request whose interaction finished the code is stored the request is decided at the finish of an interaction: the next interaction continues it INTERACTION_UI_ENABLED is off INTERACTION_UI_ENABLED is on INTERACTION_UI_ENABLED is off, and the consent was revoked under the request INTERACTION_UI_ENABLED is off the consent step cannot show the scopes, decided when the interaction finished the consent step cannot show the resources, decided when the interaction finished the consent step cannot show the scopes, for a client an operator provisioned the consent step cannot show the scopes, for a client no operator provisioned the consent step cannot show the resources, for a client an operator provisioned the consent step cannot show the resources, for a client no operator provisioned the consent step can show the request, which an interaction just finished: the next one continues it the consent step can show the request the request is parked, for a request with no session the request is parked, for a cookie of no usable session the request is parked, for a session that ended under it the request is parked, for a step-up the interaction is stored the interaction is stored the person's last answer, such as the right password, finishes the interaction the person cancels, with the CSRF value of the step they see; the interaction ends the person answers the consent step the person cancels, with the CSRF value of the step they see; the interaction ends the client, or its redirect URI, no longer passes the client may no longer use the endpoint the request still passes the interaction is over the client, or its redirect URI, no longer passes the client may no longer use the endpoint the request still passes the session is no longer usable: the request needs a sign-in again the session is live: the request is decided again for it the next interaction is stored the next interaction is stored start idle Wait for an authorization request idle · server step The realm resolver's onRequest hook, before any route code. /oauth/authorize is a browser route, so it answers on the realm's primary host only. A request refused here is never counted by the rate limiter. Find the realm of the host resolvingRealm · server step AUTHORIZE_RATE_LIMIT requests per AUTHORIZE_RATE_WINDOW seconds for each client address and realm, the lenient AUTHORIZE_RATE_LIMIT_LENIENT where the realm's ceiling permits a development environment (ADR-008 §5). Every request that starts an interaction writes a record and its events, so this limit bounds them too. Count the request against the authorize limit rateLimiting · server step authorizeQuerySchema, for the query of a GET and the form of a POST alike: response_type code, client_id, redirect_uri, code_challenge and code_challenge_method S256 (PKCE), and the optional scope, state, nonce, prompt, max_age, resource, dpop_jkt and login_hint (at most 254 bytes in UTF-8, #628). Check the parameters against the authorize schema validatingParameters · server step A pre-registered client first; otherwise a URL client_id is resolved as a CIMD document, fetched through the egress client and materialised as a row. authorization.failed is recorded for every refusal of this and the next checks. Find the client resolvingClient · server step An exact match; a loopback URI may differ only in its port (RFC 8252 §7.3). Check the redirect URI against the client's registration checkingRedirectUri · server step ADR-008 §5 (#197): the effective environment of the client and its realm, then the scheme and plain-http gate. Refused before any redirect, since the redirect target is what is under suspicion. Check the redirect URI against the environment policy checkingEnvironment · server step A disabled or suspended client, and one not registered for the authorization_code grant or the code response type, are answered with a 400 that never redirects, whoever provisioned them (RFC 9700 §4.11.2). Check that the client may use the endpoint checkingClientGrant · server step RFC 9449 §10 (#480), read only while DPoP is on. This is the last check that needs no user: an interaction is created only for a request that passed every one before it, client_id, redirect_uri and PKCE included. Read the DPoP key the code is to be bound to readingDpopKey · server step prompt=create (#640; OpenID Connect Prompt Create 1.0; ADR-017 Decisions 3 and 8), refused before the person sees any page unless the request asks for openid, the realm offers sign-up (its accounts.allowSignUp, served by the Interaction API, so never with INTERACTION_UI_ENABLED off), the client's operator-set hosted_flows name register, and the request carries no max_age, which asks for a sign-in a registration never gives. Each refusal records authorization.failed with its reason. A browser session, if any, is read and carried in; it ends nothing. Check a request for a registration checkingCreatePrompt · server step As a sign-in interaction, at the identifier step alone, the request held without prompt=create's routing to an upstream provider (qauth_upstream): the engine's rounds are core.sign-up's. The request's login_hint fills in the address. A browser already signed in registers all the same; its session is carried, not ended. Start a registration interaction startingRegistration · server step The steps of the registration are core.sign-up's: the address, an emailed code, a new password. The answer that creates the account finishes the interaction with no session: the request is then decided again for the new account, which has no sign-in time, so a dangerous scope or a native_backend client asks for a sign-in first, and the code the endpoint mints carries no auth_time, no amr and no session. prompt=create is not carried past that finish. For an address an account holds, core.sign-up hands over to the sign-in, whose finish is a sign-in's. The person registers at the ceremony page atRegistrationCeremony · server step The signed __Host-qauth_session cookie (#150); an Authorization header counts for nothing (#524). A cookie that does not verify, or names an ended session, is cleared; a disabled user's session is ended. Find the browser session findingSession · server step ADR-007 §2 (#184). On the raw scope parameter, before the allowlist filter. Refuse an agent scope above the client's cap checkingAgentCap · server step RFC 8707 §2 (#509), before a consent screen offers what the token endpoint would refuse. Refuse a QAuth API audience the client does not list checkingAudience · server step The stored consent (findActive) and the administrative consent of an operator-flagged first-party client (ADR-017 Decision 9), then the step-up gate (evaluateStepUp, ADR-007 §2). Under prompt=none no page may be shown (OpenID Connect Core §3.1.2.1): a fresh sign-in the request needs answers login_required, and a consent it needs answers consent_required, with step_up.required recorded. Otherwise a fresh sign-in comes first, then the consent (step_up.required is recorded for both, for the consent when the request widens a prior grant). Read the consent, and decide whether the sign-in is fresh enough and the consent covers the request decidingStepUp · server step One transaction (MINT_TRANSACTION, READ COMMITTED): the consent read again FOR SHARE, so a revocation that committed since leaves no code; mintAuthorizationCode, which locks the browser session's row FOR SHARE, records the client on it and refuses a session that has ended; consent.administrative for a code the administrative consent let through; authorization.completed. The code binds the client, the user, the redirect URI, the PKCE challenge, the nonce, the scopes, the resources, the DPoP key and the session. A refusal is answered, once, as a request arriving after the sign-out or the revocation would be. Mint the authorization code under the consent and the session mintingCode · server step With the pages, the authorize URL is parked server-side and the browser goes to /ui/login. With interactions, an interaction starts at the identifier step; when an interaction just finished, the next one continues the request. Send the person to sign in signInNeeded · server step With the pages, to /ui/consent with the authorize parameters in its query (core.consent-page). With interactions, to a consent interaction for the signed-in user, which lists the scopes, marks the dangerous ones and names the resources; a request the step cannot show is refused instead, with authorization.failed recorded, as the contract says ("A requested scope outside it never reaches this step: the request is refused first"). Send the person to consent consentNeeded · server step The authorize URL, rebuilt from the validated form for a POST, is checked against 16 KiB and stored under a single-use handle for ten minutes (#316), and the browser is sent to /ui/login with /ui/resume/<handle> as its return_to, which sends it back here once signed in. Park the authorization request for the sign-in parkingRequest · server step An interaction record (#592) holding the validated request, at most 16 KiB, with the identifier step, at most 32 KiB in all, bound to this browser by a new secret in the __Host-qauth_flow cookie, alive until its first answer for INTERACTION_UNANSWERED_TTL_MS at most and INTERACTION_TTL in all; interaction.created is recorded. The request's login_hint, when the step can show it, is the identifier field's prefill, in the step's personal data (read only by the browser that holds the flow cookie), never in its params. Start a sign-in interaction startingSignIn · server step As a sign-in interaction, at the consent step, for the signed-in user: the transaction holds the browser session's user, sid and sign-in time, and the finish needs that session live (#963). Start a consent interaction startingConsent · server step The redirect carries the interaction id and nothing else: no URL carries the authorization request again, so a 2048-character state makes no longer a Location header. The ceremony page reads the step by the id and answers it through the Interaction API, from the realm origin, with the flow cookie and each step's CSRF value; the steps of the sign-in are core.sign-in's. The person signs in at the ceremony page atSignInCeremony · server step The consent step names the client as the server's records describe it (#593), lists the scopes (each marked when it is dangerous), the resources or else the client's audience, says so when the client is an AI agent, and offers "Remember this decision", checked by default. Its personal data is the identifier the user signed in with. The person is asked for consent at the ceremony page atConsentCeremony · server step cancelAuthorization: the cancel has ended the interaction, its record deleted and its secret out of the flow cookie; the request it held is checked again as the endpoint checks it, as a finish is, so a client disabled, or a redirect URI removed, since the interaction started gets no redirect. Check the request again before the cancel goes to the client recheckingCancel · server step The answer has taken the interaction's turn and its decision finishes it (#616, #963): the session its sign-in started must be live, and the record is deleted, unless the expiry sweep claimed it first; the finished interaction's secret leaves the flow cookie. Only now is the request decided again: the code is never minted while the interaction can still be answered, and a finish the sweep beat issues none. For a sign-in, the answer also carries the new session cookie, and the user's last sign-in and user.signed_in are recorded. End the interaction before anything is issued takingFinish · server step checkAuthorizationRequest on the request the record holds: the client may have been deleted, disabled or changed since the interaction started. A refusal is thrown, so nothing is sent to a redirect URI the client no longer holds. Check the request again, as the endpoint checks it recheckingRequest · server step By its sid, not by the cookie, which the answer is only now setting: live, its user's, and its account still allowed to use it (liveBrowserSession, the cookie path's rules). Find the session the interaction holds findingTransactionSession · server step continueInteraction: as a new interaction, but within the finished one's absolute expiry (one request, one lifetime) and on the flow secrets the finish left. Continue the request in a new sign-in interaction continuingToSignIn · server step As continuingToSignIn, at the consent step, for the session the finished interaction holds. Continue the request in a consent interaction continuingToConsent · server step code_issued Send the authorization code to the client redirect with code + state + iss code_issued.after_sign_in Send the authorization code to the client once the interaction finished redirect with code + state + iss sign_in_required.no_session Send a browser with no session to sign in no redirect, page shown sign_in_required.unusable_session Send a browser whose session cookie is of no use to sign in no redirect, page shown sign_in_required.fresh_login Send a browser whose sign-in is too old for the request to sign in again no redirect, page shown sign_in_required.session_ended Send a browser whose session ended under the request to sign in again no redirect, page shown consent_screen.page Send the signed-in user to the consent page no redirect, page shown consent_screen.consent_withdrawn Send the user whose consent was revoked under the request to the consent page no redirect, page shown access_denied.cancelled Tell the client the person cancelled redirect, error=access_denied core.consent draws the answer (#629): the step grammar, the finish, the request checked again, deny or allow, and the code for exactly the scope set the step showed, or the error the client gets. Leave the answer to the consent step's graph ends here The record is gone once the interaction finished, so a replayed answer issues no second code, and an id is never answered again. Refuse a request for an interaction that already finished no redirect, page shown invalid_request.client_changed Refuse a finish or a cancel whose client or redirect URI no longer passes no redirect, page shown unauthorized_client.client_changed Refuse a finish or a cancel whose client may no longer use the endpoint no redirect, page shown invalid_scope.agent_scope_mode_exceeded_after_sign_in Tell the client an agent scope is above its cap, once the person signed in redirect, error=invalid_scope invalid_target.unlisted_reserved_audience_after_sign_in Tell the client it named an audience it does not list, once the person signed in redirect, error=invalid_target invalid_scope.consent_not_shown_after_sign_in Tell the client the consent step cannot show its scopes, once the person signed in redirect, error=invalid_scope invalid_target.consent_not_shown_after_sign_in Tell the client the consent step cannot show its resources, once the person signed in redirect, error=invalid_target invalid_request.malformed_dpop_jkt Tell the client its dpop_jkt is malformed redirect, error=invalid_request invalid_request.malformed_dpop_jkt_shown Show, rather than redirect, the dpop_jkt error of a client no operator provisioned no redirect, page shown invalid_request.create_without_openid Tell the client prompt=create needs the openid scope redirect, error=invalid_request invalid_request.create_without_openid_shown Show, rather than redirect, the openid error of a client no operator provisioned no redirect, page shown invalid_request.registration_not_offered Tell the client the realm offers no sign-up redirect, error=invalid_request invalid_request.registration_not_offered_shown Show, rather than redirect, the sign-up refusal of a client no operator provisioned no redirect, page shown unauthorized_client.registration_not_allowed Tell the client it may not register accounts redirect, error=unauthorized_client unauthorized_client.registration_not_allowed_shown Show, rather than redirect, the registration refusal of a client no operator provisioned no redirect, page shown invalid_request.create_with_max_age Tell the client prompt=create takes no max_age redirect, error=invalid_request invalid_request.create_with_max_age_shown Show, rather than redirect, the max_age error of a client no operator provisioned no redirect, page shown login_required.no_session Tell the client prompt=none found no session redirect, error=login_required login_required.no_session_shown Show, rather than redirect, the login_required of a client no operator provisioned no redirect, page shown invalid_scope.agent_scope_mode_exceeded Tell the client an agent scope is above its cap redirect, error=invalid_scope invalid_scope.agent_scope_mode_exceeded_shown Show, rather than redirect, the agent-cap error of a client no operator provisioned no redirect, page shown invalid_target.unlisted_reserved_audience Tell the client it named a QAuth API audience it does not list redirect, error=invalid_target invalid_target.unlisted_reserved_audience_shown Show, rather than redirect, the audience error of a client no operator provisioned no redirect, page shown login_required.fresh_login Tell the client prompt=none cannot give the fresh sign-in the request needs redirect, error=login_required login_required.fresh_login_shown Show, rather than redirect, that error for a client no operator provisioned no redirect, page shown consent_required.prompt_none Tell the client prompt=none cannot ask for the consent the request needs redirect, error=consent_required consent_required.prompt_none_shown Show, rather than redirect, that error for a client no operator provisioned no redirect, page shown invalid_scope.consent_not_shown Tell the client the consent step cannot show its scopes redirect, error=invalid_scope invalid_scope.consent_not_shown_shown Show, rather than redirect, that error for a client no operator provisioned no redirect, page shown invalid_target.consent_not_shown Tell the client the consent step cannot show its resources redirect, error=invalid_target invalid_target.consent_not_shown_shown Show, rather than redirect, that error for a client no operator provisioned no redirect, page shown invalid_request.schema Refuse parameters the schema does not accept no redirect, page shown invalid_request.unknown_client Refuse a client_id that names no client no redirect, page shown invalid_request.redirect_uri_not_registered Refuse a redirect URI the client did not register no redirect, page shown invalid_request.redirect_uri_not_permitted Refuse a redirect URI no environment permits no redirect, page shown unauthorized_client.disabled Refuse a disabled or suspended client no redirect, page shown unauthorized_client.grant_type Refuse a client not registered for the authorization_code grant no redirect, page shown unauthorized_client.response_type Refuse a client not registered for the code response type no redirect, page shown misdirected_request.host Refuse a host this server does not answer for here no redirect, page shown too_many_requests.authorize_limit Refuse an address over the authorize limit no redirect, page shown server_error.malformed_cookie Fail a request whose session cookie cannot be decoded no redirect, page shown
GET /oauth/authorize arrives with its parameters in the query, or POST with them in a form an answer, a cancel or a read names an interaction of this request that already finished, such as a replayed or a second form post the host names no enabled realm with an issuer, or is one of its endpoint hosts the request has its realm the address has used up its requests the address is under its limit the parameters do not match the schema the parameters match the schema the client_id names no client of the realm the client is found redirect_uri is not registered for the client redirect_uri is registered no environment permits that redirect_uri the environment permits the redirect URI the client is disabled or suspended the client is not registered for the authorization_code grant the client is not registered for the code response type the client may use the endpoint dpop_jkt is not one thumbprint, for a client an operator provisioned dpop_jkt is not one thumbprint, for a client no operator provisioned dpop_jkt is absent, unread or well formed the request carries no prompt=create prompt=create without openid, for a client an operator provisioned prompt=create without openid, for a client no operator provisioned the realm offers no sign-up, for a client an operator provisioned the realm offers no sign-up, for a client no operator provisioned the client may not register accounts, for a client an operator provisioned the client may not register accounts, for a client no operator provisioned prompt=create with max_age, for a client an operator provisioned prompt=create with max_age, for a client no operator provisioned the session cookie cannot be decoded the registration is allowed the interaction is stored fails: the request is over 16 KiB, or the record over 32 KiB fails: the interaction store fails the new password creates the account, which finishes the interaction the person cancels, with the CSRF value of the step they see; the interaction ends the session cookie cannot be decoded no usable session under prompt=none, for a client an operator provisioned; step_up.required is recorded no usable session under prompt=none, for a client no operator provisioned no usable session: the person signs in first, and the request is decided again with that session the session is live an agent scope is above the cap, decided when the interaction finished an agent scope is above the cap, for a client an operator provisioned an agent scope is above the cap, for a client no operator provisioned no agent scope is above the cap; the scopes are the requested ones the client's allowlist holds a resource names a QAuth API audience the client does not list, decided when the interaction finished a resource names a QAuth API audience the client does not list, for a client an operator provisioned a resource names a QAuth API audience the client does not list, for a client no operator provisioned every QAuth API audience among the resources is one the client lists prompt=none, and the sign-in is too old for what is asked, for a client an operator provisioned prompt=none, and the sign-in is too old for what is asked, for a client no operator provisioned prompt=none, and no consent covers the request, for a client an operator provisioned prompt=none, and no consent covers the request, for a client no operator provisioned the sign-in is too old for what is asked: the person signs in again no consent covers the request: the person is asked the sign-in is fresh enough and a consent covers the request the code is stored, for the request whose interaction finished the code is stored fails: the session ended under the request, under prompt=none, for a client an operator provisioned fails: the session ended under the request, under prompt=none, for a client no operator provisioned fails: the session ended under the request: the person signs in again fails: the consent was revoked under the request, under prompt=none, for a client an operator provisioned fails: the consent was revoked under the request, under prompt=none, for a client no operator provisioned fails: the consent was revoked under the request: the person is asked again fails: the database fails, when the interaction finished fails: the database fails the request is decided at the finish of an interaction: the next interaction continues it INTERACTION_UI_ENABLED is off INTERACTION_UI_ENABLED is on INTERACTION_UI_ENABLED is off, and the consent was revoked under the request INTERACTION_UI_ENABLED is off the consent step cannot show the scopes, decided when the interaction finished the consent step cannot show the resources, decided when the interaction finished the consent step cannot show the scopes, for a client an operator provisioned the consent step cannot show the scopes, for a client no operator provisioned the consent step cannot show the resources, for a client an operator provisioned the consent step cannot show the resources, for a client no operator provisioned the consent step can show the request, which an interaction just finished: the next one continues it the consent step can show the request the request is parked, for a request with no session the request is parked, for a cookie of no usable session the request is parked, for a session that ended under it the request is parked, for a step-up fails: the rebuilt request is over 16 KiB the interaction is stored fails: the request is over 16 KiB, or the record over 32 KiB fails: the interaction store fails the interaction is stored fails: the request is over 16 KiB, or the record over 32 KiB fails: the interaction store fails the person's last answer, such as the right password, finishes the interaction the person cancels, with the CSRF value of the step they see; the interaction ends the person answers the consent step the person cancels, with the CSRF value of the step they see; the interaction ends the client, or its redirect URI, no longer passes the client may no longer use the endpoint the request still passes the interaction is over fails: the expiry sweep claimed the interaction first fails: the session the sign-in started has ended since, such as by a sign-out in another tab fails: the interaction store fails; the turn is given back the client, or its redirect URI, no longer passes the client may no longer use the endpoint the request still passes the session is no longer usable: the request needs a sign-in again the session is live: the request is decided again for it the next interaction is stored fails: the record of the next interaction is over 32 KiB fails: the interaction store fails the next interaction is stored fails: the record of the next interaction is over 32 KiB fails: the interaction store fails start idle Wait for an authorization request idle · server step The realm resolver's onRequest hook, before any route code. /oauth/authorize is a browser route, so it answers on the realm's primary host only. A request refused here is never counted by the rate limiter. Find the realm of the host resolvingRealm · server step AUTHORIZE_RATE_LIMIT requests per AUTHORIZE_RATE_WINDOW seconds for each client address and realm, the lenient AUTHORIZE_RATE_LIMIT_LENIENT where the realm's ceiling permits a development environment (ADR-008 §5). Every request that starts an interaction writes a record and its events, so this limit bounds them too. Count the request against the authorize limit rateLimiting · server step authorizeQuerySchema, for the query of a GET and the form of a POST alike: response_type code, client_id, redirect_uri, code_challenge and code_challenge_method S256 (PKCE), and the optional scope, state, nonce, prompt, max_age, resource, dpop_jkt and login_hint (at most 254 bytes in UTF-8, #628). Check the parameters against the authorize schema validatingParameters · server step A pre-registered client first; otherwise a URL client_id is resolved as a CIMD document, fetched through the egress client and materialised as a row. authorization.failed is recorded for every refusal of this and the next checks. Find the client resolvingClient · server step An exact match; a loopback URI may differ only in its port (RFC 8252 §7.3). Check the redirect URI against the client's registration checkingRedirectUri · server step ADR-008 §5 (#197): the effective environment of the client and its realm, then the scheme and plain-http gate. Refused before any redirect, since the redirect target is what is under suspicion. Check the redirect URI against the environment policy checkingEnvironment · server step A disabled or suspended client, and one not registered for the authorization_code grant or the code response type, are answered with a 400 that never redirects, whoever provisioned them (RFC 9700 §4.11.2). Check that the client may use the endpoint checkingClientGrant · server step RFC 9449 §10 (#480), read only while DPoP is on. This is the last check that needs no user: an interaction is created only for a request that passed every one before it, client_id, redirect_uri and PKCE included. Read the DPoP key the code is to be bound to readingDpopKey · server step prompt=create (#640; OpenID Connect Prompt Create 1.0; ADR-017 Decisions 3 and 8), refused before the person sees any page unless the request asks for openid, the realm offers sign-up (its accounts.allowSignUp, served by the Interaction API, so never with INTERACTION_UI_ENABLED off), the client's operator-set hosted_flows name register, and the request carries no max_age, which asks for a sign-in a registration never gives. Each refusal records authorization.failed with its reason. A browser session, if any, is read and carried in; it ends nothing. Check a request for a registration checkingCreatePrompt · server step As a sign-in interaction, at the identifier step alone, the request held without prompt=create's routing to an upstream provider (qauth_upstream): the engine's rounds are core.sign-up's. The request's login_hint fills in the address. A browser already signed in registers all the same; its session is carried, not ended. Start a registration interaction startingRegistration · server step The steps of the registration are core.sign-up's: the address, an emailed code, a new password. The answer that creates the account finishes the interaction with no session: the request is then decided again for the new account, which has no sign-in time, so a dangerous scope or a native_backend client asks for a sign-in first, and the code the endpoint mints carries no auth_time, no amr and no session. prompt=create is not carried past that finish. For an address an account holds, core.sign-up hands over to the sign-in, whose finish is a sign-in's. The person registers at the ceremony page atRegistrationCeremony · server step The signed __Host-qauth_session cookie (#150); an Authorization header counts for nothing (#524). A cookie that does not verify, or names an ended session, is cleared; a disabled user's session is ended. Find the browser session findingSession · server step ADR-007 §2 (#184). On the raw scope parameter, before the allowlist filter. Refuse an agent scope above the client's cap checkingAgentCap · server step RFC 8707 §2 (#509), before a consent screen offers what the token endpoint would refuse. Refuse a QAuth API audience the client does not list checkingAudience · server step The stored consent (findActive) and the administrative consent of an operator-flagged first-party client (ADR-017 Decision 9), then the step-up gate (evaluateStepUp, ADR-007 §2). Under prompt=none no page may be shown (OpenID Connect Core §3.1.2.1): a fresh sign-in the request needs answers login_required, and a consent it needs answers consent_required, with step_up.required recorded. Otherwise a fresh sign-in comes first, then the consent (step_up.required is recorded for both, for the consent when the request widens a prior grant). Read the consent, and decide whether the sign-in is fresh enough and the consent covers the request decidingStepUp · server step One transaction (MINT_TRANSACTION, READ COMMITTED): the consent read again FOR SHARE, so a revocation that committed since leaves no code; mintAuthorizationCode, which locks the browser session's row FOR SHARE, records the client on it and refuses a session that has ended; consent.administrative for a code the administrative consent let through; authorization.completed. The code binds the client, the user, the redirect URI, the PKCE challenge, the nonce, the scopes, the resources, the DPoP key and the session. A refusal is answered, once, as a request arriving after the sign-out or the revocation would be. Mint the authorization code under the consent and the session mintingCode · server step With the pages, the authorize URL is parked server-side and the browser goes to /ui/login. With interactions, an interaction starts at the identifier step; when an interaction just finished, the next one continues the request. Send the person to sign in signInNeeded · server step With the pages, to /ui/consent with the authorize parameters in its query (core.consent-page). With interactions, to a consent interaction for the signed-in user, which lists the scopes, marks the dangerous ones and names the resources; a request the step cannot show is refused instead, with authorization.failed recorded, as the contract says ("A requested scope outside it never reaches this step: the request is refused first"). Send the person to consent consentNeeded · server step The authorize URL, rebuilt from the validated form for a POST, is checked against 16 KiB and stored under a single-use handle for ten minutes (#316), and the browser is sent to /ui/login with /ui/resume/<handle> as its return_to, which sends it back here once signed in. Park the authorization request for the sign-in parkingRequest · server step An interaction record (#592) holding the validated request, at most 16 KiB, with the identifier step, at most 32 KiB in all, bound to this browser by a new secret in the __Host-qauth_flow cookie, alive until its first answer for INTERACTION_UNANSWERED_TTL_MS at most and INTERACTION_TTL in all; interaction.created is recorded. The request's login_hint, when the step can show it, is the identifier field's prefill, in the step's personal data (read only by the browser that holds the flow cookie), never in its params. Start a sign-in interaction startingSignIn · server step As a sign-in interaction, at the consent step, for the signed-in user: the transaction holds the browser session's user, sid and sign-in time, and the finish needs that session live (#963). Start a consent interaction startingConsent · server step The redirect carries the interaction id and nothing else: no URL carries the authorization request again, so a 2048-character state makes no longer a Location header. The ceremony page reads the step by the id and answers it through the Interaction API, from the realm origin, with the flow cookie and each step's CSRF value; the steps of the sign-in are core.sign-in's. The person signs in at the ceremony page atSignInCeremony · server step The consent step names the client as the server's records describe it (#593), lists the scopes (each marked when it is dangerous), the resources or else the client's audience, says so when the client is an AI agent, and offers "Remember this decision", checked by default. Its personal data is the identifier the user signed in with. The person is asked for consent at the ceremony page atConsentCeremony · server step cancelAuthorization: the cancel has ended the interaction, its record deleted and its secret out of the flow cookie; the request it held is checked again as the endpoint checks it, as a finish is, so a client disabled, or a redirect URI removed, since the interaction started gets no redirect. Check the request again before the cancel goes to the client recheckingCancel · server step The answer has taken the interaction's turn and its decision finishes it (#616, #963): the session its sign-in started must be live, and the record is deleted, unless the expiry sweep claimed it first; the finished interaction's secret leaves the flow cookie. Only now is the request decided again: the code is never minted while the interaction can still be answered, and a finish the sweep beat issues none. For a sign-in, the answer also carries the new session cookie, and the user's last sign-in and user.signed_in are recorded. End the interaction before anything is issued takingFinish · server step checkAuthorizationRequest on the request the record holds: the client may have been deleted, disabled or changed since the interaction started. A refusal is thrown, so nothing is sent to a redirect URI the client no longer holds. Check the request again, as the endpoint checks it recheckingRequest · server step By its sid, not by the cookie, which the answer is only now setting: live, its user's, and its account still allowed to use it (liveBrowserSession, the cookie path's rules). Find the session the interaction holds findingTransactionSession · server step continueInteraction: as a new interaction, but within the finished one's absolute expiry (one request, one lifetime) and on the flow secrets the finish left. Continue the request in a new sign-in interaction continuingToSignIn · server step As continuingToSignIn, at the consent step, for the session the finished interaction holds. Continue the request in a consent interaction continuingToConsent · server step code_issued Send the authorization code to the client redirect with code + state + iss code_issued.after_sign_in Send the authorization code to the client once the interaction finished redirect with code + state + iss sign_in_required.no_session Send a browser with no session to sign in no redirect, page shown sign_in_required.unusable_session Send a browser whose session cookie is of no use to sign in no redirect, page shown sign_in_required.fresh_login Send a browser whose sign-in is too old for the request to sign in again no redirect, page shown sign_in_required.session_ended Send a browser whose session ended under the request to sign in again no redirect, page shown consent_screen.page Send the signed-in user to the consent page no redirect, page shown consent_screen.consent_withdrawn Send the user whose consent was revoked under the request to the consent page no redirect, page shown access_denied.cancelled Tell the client the person cancelled redirect, error=access_denied core.consent draws the answer (#629): the step grammar, the finish, the request checked again, deny or allow, and the code for exactly the scope set the step showed, or the error the client gets. Leave the answer to the consent step's graph ends here The record is gone once the interaction finished, so a replayed answer issues no second code, and an id is never answered again. Refuse a request for an interaction that already finished no redirect, page shown The sweep reports the interaction expired; nothing is issued. Refuse a finish the expiry sweep beat no redirect, page shown Nothing is written; the turn is given back (#963). Refuse a finish whose session ended since no redirect, page shown invalid_request.client_changed Refuse a finish or a cancel whose client or redirect URI no longer passes no redirect, page shown unauthorized_client.client_changed Refuse a finish or a cancel whose client may no longer use the endpoint no redirect, page shown invalid_request.authorization_too_large_after_sign_in Refuse a next interaction too large to hold no redirect, page shown server_error.interaction_store_after_sign_in Fail the answer when the interaction store fails no redirect, page shown server_error.store_after_sign_in Fail the answer when the database fails at the mint no redirect, page shown invalid_scope.agent_scope_mode_exceeded_after_sign_in Tell the client an agent scope is above its cap, once the person signed in redirect, error=invalid_scope invalid_target.unlisted_reserved_audience_after_sign_in Tell the client it named an audience it does not list, once the person signed in redirect, error=invalid_target invalid_scope.consent_not_shown_after_sign_in Tell the client the consent step cannot show its scopes, once the person signed in redirect, error=invalid_scope invalid_target.consent_not_shown_after_sign_in Tell the client the consent step cannot show its resources, once the person signed in redirect, error=invalid_target invalid_request.malformed_dpop_jkt Tell the client its dpop_jkt is malformed redirect, error=invalid_request invalid_request.malformed_dpop_jkt_shown Show, rather than redirect, the dpop_jkt error of a client no operator provisioned no redirect, page shown invalid_request.create_without_openid Tell the client prompt=create needs the openid scope redirect, error=invalid_request invalid_request.create_without_openid_shown Show, rather than redirect, the openid error of a client no operator provisioned no redirect, page shown invalid_request.registration_not_offered Tell the client the realm offers no sign-up redirect, error=invalid_request invalid_request.registration_not_offered_shown Show, rather than redirect, the sign-up refusal of a client no operator provisioned no redirect, page shown unauthorized_client.registration_not_allowed Tell the client it may not register accounts redirect, error=unauthorized_client unauthorized_client.registration_not_allowed_shown Show, rather than redirect, the registration refusal of a client no operator provisioned no redirect, page shown invalid_request.create_with_max_age Tell the client prompt=create takes no max_age redirect, error=invalid_request invalid_request.create_with_max_age_shown Show, rather than redirect, the max_age error of a client no operator provisioned no redirect, page shown login_required.no_session Tell the client prompt=none found no session redirect, error=login_required login_required.no_session_shown Show, rather than redirect, the login_required of a client no operator provisioned no redirect, page shown invalid_scope.agent_scope_mode_exceeded Tell the client an agent scope is above its cap redirect, error=invalid_scope invalid_scope.agent_scope_mode_exceeded_shown Show, rather than redirect, the agent-cap error of a client no operator provisioned no redirect, page shown invalid_target.unlisted_reserved_audience Tell the client it named a QAuth API audience it does not list redirect, error=invalid_target invalid_target.unlisted_reserved_audience_shown Show, rather than redirect, the audience error of a client no operator provisioned no redirect, page shown login_required.fresh_login Tell the client prompt=none cannot give the fresh sign-in the request needs redirect, error=login_required login_required.fresh_login_shown Show, rather than redirect, that error for a client no operator provisioned no redirect, page shown consent_required.prompt_none Tell the client prompt=none cannot ask for the consent the request needs redirect, error=consent_required consent_required.prompt_none_shown Show, rather than redirect, that error for a client no operator provisioned no redirect, page shown login_required.session_ended Tell the client under prompt=none that the session ended under the request redirect, error=login_required login_required.session_ended_shown Show, rather than redirect, that error for a client no operator provisioned no redirect, page shown consent_required.consent_withdrawn Tell the client under prompt=none that the consent was revoked under the request redirect, error=consent_required consent_required.consent_withdrawn_shown Show, rather than redirect, that error for a client no operator provisioned no redirect, page shown invalid_scope.consent_not_shown Tell the client the consent step cannot show its scopes redirect, error=invalid_scope invalid_scope.consent_not_shown_shown Show, rather than redirect, that error for a client no operator provisioned no redirect, page shown invalid_target.consent_not_shown Tell the client the consent step cannot show its resources redirect, error=invalid_target invalid_target.consent_not_shown_shown Show, rather than redirect, that error for a client no operator provisioned no redirect, page shown invalid_request.schema Refuse parameters the schema does not accept no redirect, page shown invalid_request.unknown_client Refuse a client_id that names no client no redirect, page shown invalid_request.redirect_uri_not_registered Refuse a redirect URI the client did not register no redirect, page shown invalid_request.redirect_uri_not_permitted Refuse a redirect URI no environment permits no redirect, page shown unauthorized_client.disabled Refuse a disabled or suspended client no redirect, page shown unauthorized_client.grant_type Refuse a client not registered for the authorization_code grant no redirect, page shown unauthorized_client.response_type Refuse a client not registered for the code response type no redirect, page shown The pending-authorization stash holds a rebuilt URL of 16 KiB at most; an interaction record, a request of 16 KiB and a record of 32 KiB. Refuse a request too large to hold through the sign-in or the consent no redirect, page shown misdirected_request.host Refuse a host this server does not answer for here no redirect, page shown too_many_requests.authorize_limit Refuse an address over the authorize limit no redirect, page shown server_error.malformed_cookie Fail a request whose session cookie cannot be decoded no redirect, page shown server_error.store Fail the request when the database fails at the mint no redirect, page shown server_error.interaction_store Fail the request when the interaction store fails no redirect, page shown

blue line: the main storyred dashed line: a failure path (shown with “Show failure paths”)dotted line: decided by a rule, nobody actsdashed grey box: the server decides, nothing is showngreen exit: successred exit: no redirect

What each step answers

StepThe outside world sees
The person registers at the ceremony page
atRegistrationCeremony
302 from /oauth/authorize; 303 or 200 from the Interaction API when an interaction finished · headers: {"Location":"/ui/interaction/<the interaction id, 43 base64url characters>, from /oauth/authorize; the same path on the realm's issuer, when an interaction finished","Set-Cookie":"__Host-qauth_flow=<the browser's interaction secrets, this one's added>; Path=/; HttpOnly; SameSite=Lax, and the session cookie cleared when the request carried an unusable one"} · body: none from /oauth/authorize; from the Interaction API, a form post gets the redirect and a JSON answer { result: redirect, location }
The person signs in at the ceremony page
atSignInCeremony
302 from /oauth/authorize; 303 or 200 from the Interaction API when an interaction finished · headers: {"Location":"/ui/interaction/<the interaction id, 43 base64url characters>, from /oauth/authorize; the same path on the realm's issuer, when an interaction finished","Set-Cookie":"__Host-qauth_flow=<the browser's interaction secrets, this one's added>; Path=/; HttpOnly; SameSite=Lax, and the session cookie cleared when the request carried an unusable one"} · body: none from /oauth/authorize; from the Interaction API, a form post gets the redirect and a JSON answer { result: redirect, location }
The person is asked for consent at the ceremony page
atConsentCeremony
as atSignInCeremony · headers: {"Location":"as atSignInCeremony","Set-Cookie":"__Host-qauth_flow=<the browser's interaction secrets, this one's added>; Path=/; HttpOnly; SameSite=Lax"} · body: as atSignInCeremony
Send the authorization code to the client
code_issued
302 · headers: {"Location":"redirect_uri with code (43 base64url characters), state when the request had one, and iss"}
Send the authorization code to the client once the interaction finished
code_issued.after_sign_in
303 for a form post; 200 for a JSON answer · headers: {"Location":"for a form post, redirect_uri with code (43 base64url characters), state when the request had one, and iss","Set-Cookie":"the new session cookie, and __Host-qauth_flow without the finished interaction's secret","Cache-Control":"no-store"} · body: for a JSON answer, { result: redirect, location: the same URL }
Send a browser with no session to sign in
sign_in_required.no_session
302 · headers: {"Location":"/ui/login?return_to=<percent-encoded /ui/resume/<handle>>"}
Send a browser whose session cookie is of no use to sign in
sign_in_required.unusable_session
302 · headers: {"Location":"/ui/login?return_to=<percent-encoded /ui/resume/<handle>>","Set-Cookie":"__Host-qauth_session cleared (Max-Age=0)"}
Send a browser whose sign-in is too old for the request to sign in again
sign_in_required.fresh_login
302 · headers: {"Location":"/ui/login?return_to=<percent-encoded /ui/resume/<handle>>"}
Send a browser whose session ended under the request to sign in again
sign_in_required.session_ended
302 · headers: {"Location":"/ui/login?return_to=<percent-encoded /ui/resume/<handle>>"}
Send the signed-in user to the consent page
consent_screen.page
302 · headers: {"Location":"/ui/consent?<the authorize parameters, as the request carried them>"}
Send the user whose consent was revoked under the request to the consent page
consent_screen.consent_withdrawn
302 · headers: {"Location":"/ui/consent?<the authorize parameters, as the request carried them>"}
Tell the client the person cancelled
access_denied.cancelled
303 for a form post; 200 for a JSON cancel · headers: {"Location":"for a form post, redirect_uri with error=access_denied, state when the request had one, and iss","Set-Cookie":"__Host-qauth_flow without the cancelled interaction's secret"} · body: for a JSON cancel, { result: redirect, location: the same URL }
Refuse a request for an interaction that already finished
interaction_expired.finished
410 · headers: {"Content-Type":"application/problem+json","Cache-Control":"no-store"} · body: {"type":"https://docs.qauth.dev/reference/problem-types/#interaction-expired","status":410,"code":"interaction_expired","trace_id":"the request id"}
Refuse a finish the expiry sweep beat
interaction_expired.finished_late
410 · headers: {"Content-Type":"application/problem+json","Cache-Control":"no-store"} · body: {"type":"https://docs.qauth.dev/reference/problem-types/#interaction-expired","status":410,"code":"interaction_expired","trace_id":"the request id"}
Refuse a finish whose session ended since
interaction_expired.session_ended
410 · headers: {"Content-Type":"application/problem+json","Cache-Control":"no-store"} · body: {"type":"https://docs.qauth.dev/reference/problem-types/#interaction-expired","status":410,"code":"interaction_expired","trace_id":"the request id"}
Refuse a finish or a cancel whose client or redirect URI no longer passes
invalid_request.client_changed
400 · headers: {"Content-Type":"application/problem+json","Cache-Control":"no-store"} · body: {"type":"https://docs.qauth.dev/reference/problem-types/#invalid-request","status":400,"code":"invalid_request","trace_id":"the request id"}
Refuse a finish or a cancel whose client may no longer use the endpoint
unauthorized_client.client_changed
400 · headers: {"Content-Type":"application/problem+json","Cache-Control":"no-store"} · body: {"type":"https://docs.qauth.dev/reference/problem-types/#unauthorized-client","status":400,"code":"unauthorized_client","trace_id":"the request id"}
Refuse a next interaction too large to hold
invalid_request.authorization_too_large_after_sign_in
400 · headers: {"Content-Type":"application/problem+json","Cache-Control":"no-store"} · body: {"type":"https://docs.qauth.dev/reference/problem-types/#invalid-request","status":400,"code":"invalid_request","trace_id":"the request id"}
Fail the answer when the interaction store fails
server_error.interaction_store_after_sign_in
500 · headers: {"Content-Type":"application/problem+json"} · body: {"type":"https://docs.qauth.dev/reference/problem-types/#internal-error","status":500,"code":"internal_error","trace_id":"the request id"}
Fail the answer when the database fails at the mint
server_error.store_after_sign_in
500 · headers: {"Content-Type":"application/problem+json"} · body: {"type":"https://docs.qauth.dev/reference/problem-types/#internal-error","status":500,"code":"internal_error","trace_id":"the request id"}
Tell the client an agent scope is above its cap, once the person signed in
invalid_scope.agent_scope_mode_exceeded_after_sign_in
303 for a form post; 200 for a JSON answer · headers: {"Location":"for a form post, redirect_uri with error=invalid_scope, error_description=requested scope exceeds the agent scope mode for this client, state when the request had one, and iss"} · body: for a JSON answer, { result: redirect, location: the same URL }
Tell the client it named an audience it does not list, once the person signed in
invalid_target.unlisted_reserved_audience_after_sign_in
303 for a form post; 200 for a JSON answer · headers: {"Location":"for a form post, redirect_uri with error=invalid_target, error_description=a QAuth API audience is issued only to a client that lists it, state when the request had one, and iss"} · body: for a JSON answer, { result: redirect, location: the same URL }
Tell the client the consent step cannot show its scopes, once the person signed in
invalid_scope.consent_not_shown_after_sign_in
303 for a form post; 200 for a JSON answer · headers: {"Location":"for a form post, redirect_uri with error=invalid_scope, error_description=the requested scopes cannot be shown for consent, state when the request had one, and iss"} · body: for a JSON answer, { result: redirect, location: the same URL }
Tell the client the consent step cannot show its resources, once the person signed in
invalid_target.consent_not_shown_after_sign_in
303 for a form post; 200 for a JSON answer · headers: {"Location":"for a form post, redirect_uri with error=invalid_target, error_description=the requested resources cannot be shown for consent, state when the request had one, and iss"} · body: for a JSON answer, { result: redirect, location: the same URL }
Tell the client its dpop_jkt is malformed
invalid_request.malformed_dpop_jkt
302 · headers: {"Location":"redirect_uri with error=invalid_request, error_description=dpop_jkt must be the base64url SHA-256 JWK thumbprint of a DPoP key, state when the request had one, and iss"}
Show, rather than redirect, the dpop_jkt error of a client no operator provisioned
invalid_request.malformed_dpop_jkt_shown
400 · headers: {"Content-Type":"text/html; charset=utf-8","Cache-Control":"no-store"} · body: a page titled "Sign-in not completed" that names the error with its description and the host of redirect_uri, and, for an http(s) redirect URI, a link "Continue to <host>" carrying the whole error response
Tell the client prompt=create needs the openid scope
invalid_request.create_without_openid
302 · headers: {"Location":"redirect_uri with error=invalid_request, error_description=prompt=create requires the openid scope, state when the request had one, and iss"}
Show, rather than redirect, the openid error of a client no operator provisioned
invalid_request.create_without_openid_shown
400 · headers: {"Content-Type":"text/html; charset=utf-8","Cache-Control":"no-store"} · body: a page titled "Sign-in not completed" that names the error with its description and the host of redirect_uri, and, for an http(s) redirect URI, a link "Continue to <host>" carrying the whole error response
Tell the client the realm offers no sign-up
invalid_request.registration_not_offered
302 · headers: {"Location":"redirect_uri with error=invalid_request, error_description=prompt=create is not supported, state when the request had one, and iss"}
Show, rather than redirect, the sign-up refusal of a client no operator provisioned
invalid_request.registration_not_offered_shown
400 · headers: {"Content-Type":"text/html; charset=utf-8","Cache-Control":"no-store"} · body: a page titled "Sign-in not completed" that names the error with its description and the host of redirect_uri, and, for an http(s) redirect URI, a link "Continue to <host>" carrying the whole error response
Tell the client it may not register accounts
unauthorized_client.registration_not_allowed
302 · headers: {"Location":"redirect_uri with error=unauthorized_client, error_description=the client may not register accounts, state when the request had one, and iss"}
Show, rather than redirect, the registration refusal of a client no operator provisioned
unauthorized_client.registration_not_allowed_shown
400 · headers: {"Content-Type":"text/html; charset=utf-8","Cache-Control":"no-store"} · body: a page titled "Sign-in not completed" that names the error with its description and the host of redirect_uri, and, for an http(s) redirect URI, a link "Continue to <host>" carrying the whole error response
Tell the client prompt=create takes no max_age
invalid_request.create_with_max_age
302 · headers: {"Location":"redirect_uri with error=invalid_request, error_description=prompt=create cannot be combined with max_age, state when the request had one, and iss"}
Show, rather than redirect, the max_age error of a client no operator provisioned
invalid_request.create_with_max_age_shown
400 · headers: {"Content-Type":"text/html; charset=utf-8","Cache-Control":"no-store"} · body: a page titled "Sign-in not completed" that names the error with its description and the host of redirect_uri, and, for an http(s) redirect URI, a link "Continue to <host>" carrying the whole error response
Tell the client prompt=none found no session
login_required.no_session
302 · headers: {"Location":"redirect_uri with error=login_required, error_description=authentication is required but prompt=none was requested, state when the request had one, and iss","Set-Cookie":"__Host-qauth_session cleared (Max-Age=0), when the request carried a cookie of no usable session"}
Show, rather than redirect, the login_required of a client no operator provisioned
login_required.no_session_shown
400 · headers: {"Content-Type":"text/html; charset=utf-8","Cache-Control":"no-store"} · body: a page titled "Sign-in not completed" that names the error with its description and the host of redirect_uri, and, for an http(s) redirect URI, a link "Continue to <host>" carrying the whole error response
Tell the client an agent scope is above its cap
invalid_scope.agent_scope_mode_exceeded
302 · headers: {"Location":"redirect_uri with error=invalid_scope, error_description=requested scope exceeds the agent scope mode for this client, state when the request had one, and iss"}
Show, rather than redirect, the agent-cap error of a client no operator provisioned
invalid_scope.agent_scope_mode_exceeded_shown
400 · headers: {"Content-Type":"text/html; charset=utf-8","Cache-Control":"no-store"} · body: a page titled "Sign-in not completed" that names the error with its description and the host of redirect_uri, and, for an http(s) redirect URI, a link "Continue to <host>" carrying the whole error response
Tell the client it named a QAuth API audience it does not list
invalid_target.unlisted_reserved_audience
302 · headers: {"Location":"redirect_uri with error=invalid_target, error_description=a QAuth API audience is issued only to a client that lists it, state when the request had one, and iss"}
Show, rather than redirect, the audience error of a client no operator provisioned
invalid_target.unlisted_reserved_audience_shown
400 · headers: {"Content-Type":"text/html; charset=utf-8","Cache-Control":"no-store"} · body: a page titled "Sign-in not completed" that names the error with its description and the host of redirect_uri, and, for an http(s) redirect URI, a link "Continue to <host>" carrying the whole error response
Tell the client prompt=none cannot give the fresh sign-in the request needs
login_required.fresh_login
302 · headers: {"Location":"redirect_uri with error=login_required, error_description=user interaction is required but prompt=none was requested, state when the request had one, and iss"}
Show, rather than redirect, that error for a client no operator provisioned
login_required.fresh_login_shown
400 · headers: {"Content-Type":"text/html; charset=utf-8","Cache-Control":"no-store"} · body: a page titled "Sign-in not completed" that names the error with its description and the host of redirect_uri, and, for an http(s) redirect URI, a link "Continue to <host>" carrying the whole error response
Tell the client prompt=none cannot ask for the consent the request needs
consent_required.prompt_none
302 · headers: {"Location":"redirect_uri with error=consent_required, error_description=user interaction is required but prompt=none was requested, state when the request had one, and iss"}
Show, rather than redirect, that error for a client no operator provisioned
consent_required.prompt_none_shown
400 · headers: {"Content-Type":"text/html; charset=utf-8","Cache-Control":"no-store"} · body: a page titled "Sign-in not completed" that names the error with its description and the host of redirect_uri, and, for an http(s) redirect URI, a link "Continue to <host>" carrying the whole error response
Tell the client under prompt=none that the session ended under the request
login_required.session_ended
302 · headers: {"Location":"redirect_uri with error=login_required, error_description=authentication is required but prompt=none was requested, state when the request had one, and iss"}
Show, rather than redirect, that error for a client no operator provisioned
login_required.session_ended_shown
400 · headers: {"Content-Type":"text/html; charset=utf-8","Cache-Control":"no-store"} · body: a page titled "Sign-in not completed" that names the error with its description and the host of redirect_uri, and, for an http(s) redirect URI, a link "Continue to <host>" carrying the whole error response
Tell the client under prompt=none that the consent was revoked under the request
consent_required.consent_withdrawn
302 · headers: {"Location":"redirect_uri with error=consent_required, error_description=user interaction is required but prompt=none was requested, state when the request had one, and iss"}
Show, rather than redirect, that error for a client no operator provisioned
consent_required.consent_withdrawn_shown
400 · headers: {"Content-Type":"text/html; charset=utf-8","Cache-Control":"no-store"} · body: a page titled "Sign-in not completed" that names the error with its description and the host of redirect_uri, and, for an http(s) redirect URI, a link "Continue to <host>" carrying the whole error response
Tell the client the consent step cannot show its scopes
invalid_scope.consent_not_shown
302 · headers: {"Location":"redirect_uri with error=invalid_scope, error_description=the requested scopes cannot be shown for consent, state when the request had one, and iss"}
Show, rather than redirect, that error for a client no operator provisioned
invalid_scope.consent_not_shown_shown
400 · headers: {"Content-Type":"text/html; charset=utf-8","Cache-Control":"no-store"} · body: a page titled "Sign-in not completed" that names the error with its description and the host of redirect_uri, and, for an http(s) redirect URI, a link "Continue to <host>" carrying the whole error response
Tell the client the consent step cannot show its resources
invalid_target.consent_not_shown
302 · headers: {"Location":"redirect_uri with error=invalid_target, error_description=the requested resources cannot be shown for consent, state when the request had one, and iss"}
Show, rather than redirect, that error for a client no operator provisioned
invalid_target.consent_not_shown_shown
400 · headers: {"Content-Type":"text/html; charset=utf-8","Cache-Control":"no-store"} · body: a page titled "Sign-in not completed" that names the error with its description and the host of redirect_uri, and, for an http(s) redirect URI, a link "Continue to <host>" carrying the whole error response
Refuse parameters the schema does not accept
invalid_request.schema
400 · headers: {"Content-Type":"application/json; charset=utf-8"} · body: {"error":"invalid_request","error_description":"the fields the schema refused, each with its message"}
Refuse a client_id that names no client
invalid_request.unknown_client
400 · headers: {"Content-Type":"application/json; charset=utf-8"} · body: {"error":"invalid_request","error_description":"client_id does not name a client of this realm"}
Refuse a redirect URI the client did not register
invalid_request.redirect_uri_not_registered
400 · headers: {"Content-Type":"application/json; charset=utf-8"} · body: {"error":"invalid_request","error_description":"redirect_uri not registered"}
Refuse a redirect URI no environment permits
invalid_request.redirect_uri_not_permitted
400 · headers: {"Content-Type":"application/json; charset=utf-8"} · body: {"error":"invalid_request","error_description":"redirect_uri not permitted for this environment"}
Refuse a disabled or suspended client
unauthorized_client.disabled
400 · headers: {"Content-Type":"application/json; charset=utf-8"} · body: {"error":"unauthorized_client","error_description":"client is disabled"}
Refuse a client not registered for the authorization_code grant
unauthorized_client.grant_type
400 · headers: {"Content-Type":"application/json; charset=utf-8"} · body: {"error":"unauthorized_client","error_description":"client is not registered for the authorization_code grant"}
Refuse a client not registered for the code response type
unauthorized_client.response_type
400 · headers: {"Content-Type":"application/json; charset=utf-8"} · body: {"error":"unauthorized_client","error_description":"client is not registered for the code response type"}
Refuse a request too large to hold through the sign-in or the consent
invalid_request.authorization_too_large
400 · headers: {"Content-Type":"application/json; charset=utf-8"} · body: {"error":"invalid_request","error_description":"authorization request is too large"}
Refuse a host this server does not answer for here
misdirected_request.host
421 · headers: {"Content-Type":"application/json; charset=utf-8"} · body: {"error":"invalid_request","error_description":"This server does not answer for the requested host"}
Refuse an address over the authorize limit
too_many_requests.authorize_limit
429 · headers: {"Content-Type":"application/json; charset=utf-8","Retry-After":"the seconds until the window ends"} · body: {"error":"temporarily_unavailable","error_description":"the rate limiter's message, which says when to retry"}
Fail a request whose session cookie cannot be decoded
server_error.malformed_cookie
500 · headers: {"Content-Type":"application/json; charset=utf-8"} · body: {"error":"server_error"}
Fail the request when the database fails at the mint
server_error.store
500 · headers: {"Content-Type":"application/json; charset=utf-8"} · body: {"error":"server_error"}
Fail the request when the interaction store fails
server_error.interaction_store
500 · headers: {"Content-Type":"application/json; charset=utf-8"} · body: {"error":"server_error"}

How it decides what happens next

Find the realm of the host

#IfThen
1the host names no enabled realm with an issuer, or is one of its endpoint hostsRefuse a host this server does not answer for here
2the request has its realmCount the request against the authorize limit

The first matching rule wins.

Exact conditions
#ConditionGoes toSituations
1hostUnknownmisdirected_request.host23040 of 253440
2otherwiserateLimiting230400 of 253440
hostUnknown
gate == 'unknownHost'

Count the request against the authorize limit

#IfThen
1the address has used up its requestsRefuse an address over the authorize limit
2the address is under its limitCheck the parameters against the authorize schema

The first matching rule wins.

Exact conditions
#ConditionGoes toSituations
1rateLimitedtoo_many_requests.authorize_limit23040 of 230400
2otherwisevalidatingParameters207360 of 230400
rateLimited
gate == 'rateLimited'

Check the parameters against the authorize schema

#IfThen
1the parameters do not match the schemaRefuse parameters the schema does not accept
2the parameters match the schemaFind the client

The first matching rule wins.

Exact conditions
#ConditionGoes toSituations
1inputInvalidinvalid_request.schema23040 of 207360
2otherwiseresolvingClient184320 of 207360
inputInvalid
gate == 'invalidInput'

Find the client

#IfThen
1the client_id names no client of the realmRefuse a client_id that names no client
2the client is foundCheck the redirect URI against the client's registration

The first matching rule wins.

Exact conditions
#ConditionGoes toSituations
1clientUnknowninvalid_request.unknown_client23040 of 184320
2otherwisecheckingRedirectUri161280 of 184320
clientUnknown
gate == 'unknownClient'

Check the redirect URI against the client's registration

#IfThen
1redirect_uri is not registered for the clientRefuse a redirect URI the client did not register
2redirect_uri is registeredCheck the redirect URI against the environment policy

The first matching rule wins.

Exact conditions
#ConditionGoes toSituations
1redirectUnregisteredinvalid_request.redirect_uri_not_registered23040 of 161280
2otherwisecheckingEnvironment138240 of 161280
redirectUnregistered
gate == 'unregisteredRedirect'

Check the redirect URI against the environment policy

#IfThen
1no environment permits that redirect_uriRefuse a redirect URI no environment permits
2the environment permits the redirect URICheck that the client may use the endpoint

The first matching rule wins.

Exact conditions
#ConditionGoes toSituations
1redirectNotPermittedinvalid_request.redirect_uri_not_permitted23040 of 138240
2otherwisecheckingClientGrant115200 of 138240
redirectNotPermitted
gate == 'unpermittedRedirect'

Check that the client may use the endpoint

#IfThen
1the client is disabled or suspendedRefuse a disabled or suspended client
2the client is not registered for the authorization_code grantRefuse a client not registered for the authorization_code grant
3the client is not registered for the code response typeRefuse a client not registered for the code response type
4the client may use the endpointRead the DPoP key the code is to be bound to

The first matching rule wins.

Exact conditions
#ConditionGoes toSituations
1clientDisabledunauthorized_client.disabled23040 of 115200
2noCodeGrantunauthorized_client.grant_type23040 of 115200
3noCodeResponseunauthorized_client.response_type23040 of 115200
4otherwisereadingDpopKey46080 of 115200
clientDisabled
gate == 'disabledClient'
noCodeGrant
gate == 'noCodeGrant'
noCodeResponse
gate == 'noCodeResponse'

Read the DPoP key the code is to be bound to

#IfThen
1dpop_jkt is not one thumbprint, for a client an operator provisionedTell the client its dpop_jkt is malformed
2dpop_jkt is not one thumbprint, for a client no operator provisionedShow, rather than redirect, the dpop_jkt error of a client no operator provisioned
3dpop_jkt is absent, unread or well formedCheck a request for a registration

The first matching rule wins.

Exact conditions
#ConditionGoes toSituations
1dpopJktMalformed and operatorClientinvalid_request.malformed_dpop_jkt11520 of 46080
2dpopJktMalformedinvalid_request.malformed_dpop_jkt_shown11520 of 46080
3otherwisecheckingCreatePrompt23040 of 46080
dpopJktMalformed
gate == 'malformedDpopJkt'
operatorClient
provisioning == 'operator'

Check a request for a registration

#IfThen
1the request carries no prompt=createFind the browser session
2prompt=create without openid, for a client an operator provisionedTell the client prompt=create needs the openid scope
3prompt=create without openid, for a client no operator provisionedShow, rather than redirect, the openid error of a client no operator provisioned
4the realm offers no sign-up, for a client an operator provisionedTell the client the realm offers no sign-up
5the realm offers no sign-up, for a client no operator provisionedShow, rather than redirect, the sign-up refusal of a client no operator provisioned
6the client may not register accounts, for a client an operator provisionedTell the client it may not register accounts
7the client may not register accounts, for a client no operator provisionedShow, rather than redirect, the registration refusal of a client no operator provisioned
8prompt=create with max_age, for a client an operator provisionedTell the client prompt=create takes no max_age
9prompt=create with max_age, for a client no operator provisionedShow, rather than redirect, the max_age error of a client no operator provisioned
10the session cookie cannot be decodedFail a request whose session cookie cannot be decoded
11the registration is allowedStart a registration interaction

The first matching rule wins.

Exact conditions
#ConditionGoes toSituations
1create == 'absent' or silentfindingSession13440 of 23040
2create == 'withoutOpenid' and operatorClientinvalid_request.create_without_openid960 of 23040
3create == 'withoutOpenid'invalid_request.create_without_openid_shown960 of 23040
4(create == 'notOffered' or pages) and operatorClientinvalid_request.registration_not_offered2400 of 23040
5create == 'notOffered' or pagesinvalid_request.registration_not_offered_shown2400 of 23040
6create == 'clientNotAllowed' and operatorClientunauthorized_client.registration_not_allowed480 of 23040
7create == 'clientNotAllowed'unauthorized_client.registration_not_allowed_shown480 of 23040
8create == 'withMaxAge' and operatorClientinvalid_request.create_with_max_age480 of 23040
9create == 'withMaxAge'invalid_request.create_with_max_age_shown480 of 23040
10cookieMalformedserver_error.malformed_cookie240 of 23040
11otherwisestartingRegistration720 of 23040
operatorClient
provisioning == 'operator'
cookieMalformed
session == 'malformedCookie'
silent
promptNone
pages
mode == 'pages'

Find the browser session

#IfThen
1the session cookie cannot be decodedFail a request whose session cookie cannot be decoded
2no usable session under prompt=none, for a client an operator provisioned; step_up.required is recordedTell the client prompt=none found no session
3no usable session under prompt=none, for a client no operator provisionedShow, rather than redirect, the login_required of a client no operator provisioned
4no usable session: the person signs in first, and the request is decided again with that sessionSend the person to sign in
5the session is liveRefuse an agent scope above the client's cap

The first matching rule wins.

Exact conditions
#ConditionGoes toSituations
1cookieMalformedserver_error.malformed_cookie3360 of 13440
2(noSession or unusableSession) and silent and operatorClientlogin_required.no_session2880 of 13440
3(noSession or unusableSession) and silentlogin_required.no_session_shown2880 of 13440
4noSession or unusableSessionsignInNeeded960 of 13440
5otherwisecheckingAgentCap3360 of 13440
operatorClient
provisioning == 'operator'
cookieMalformed
session == 'malformedCookie'
noSession
session == 'none'
unusableSession
session == 'unusable'
silent
promptNone

Refuse an agent scope above the client's cap

#IfThen
1an agent scope is above the cap, decided when the interaction finishedTell the client an agent scope is above its cap, once the person signed in
2an agent scope is above the cap, for a client an operator provisionedTell the client an agent scope is above its cap
3an agent scope is above the cap, for a client no operator provisionedShow, rather than redirect, the agent-cap error of a client no operator provisioned
4no agent scope is above the cap; the scopes are the requested ones the client's allowlist holdsRefuse a QAuth API audience the client does not list

The first matching rule wins.

Exact conditions
#ConditionGoes toSituations
1overAgentCap and finishinginvalid_scope.agent_scope_mode_exceeded_after_sign_in32 of 3604
2overAgentCap and operatorClientinvalid_scope.agent_scope_mode_exceeded336 of 3604
3overAgentCapinvalid_scope.agent_scope_mode_exceeded_shown336 of 3604
4otherwisecheckingAudience2900 of 3604
operatorClient
provisioning == 'operator'
overAgentCap
refusal == 'overAgentCap'
finishing
phase == 'finish'

Refuse a QAuth API audience the client does not list

#IfThen
1a resource names a QAuth API audience the client does not list, decided when the interaction finishedTell the client it named an audience it does not list, once the person signed in
2a resource names a QAuth API audience the client does not list, for a client an operator provisionedTell the client it named a QAuth API audience it does not list
3a resource names a QAuth API audience the client does not list, for a client no operator provisionedShow, rather than redirect, the audience error of a client no operator provisioned
4every QAuth API audience among the resources is one the client listsRead the consent, and decide whether the sign-in is fresh enough and the consent covers the request

The first matching rule wins.

Exact conditions
#ConditionGoes toSituations
1audienceUnlisted and finishinginvalid_target.unlisted_reserved_audience_after_sign_in32 of 2900
2audienceUnlisted and operatorClientinvalid_target.unlisted_reserved_audience336 of 2900
3audienceUnlistedinvalid_target.unlisted_reserved_audience_shown336 of 2900
4otherwisedecidingStepUp2196 of 2900
operatorClient
provisioning == 'operator'
audienceUnlisted
refusal == 'unlistedAudience'
finishing
phase == 'finish'

Read the consent, and decide whether the sign-in is fresh enough and the consent covers the request

#IfThen
1prompt=none, and the sign-in is too old for what is asked, for a client an operator provisionedTell the client prompt=none cannot give the fresh sign-in the request needs
2prompt=none, and the sign-in is too old for what is asked, for a client no operator provisionedShow, rather than redirect, that error for a client no operator provisioned
3prompt=none, and no consent covers the request, for a client an operator provisionedTell the client prompt=none cannot ask for the consent the request needs
4prompt=none, and no consent covers the request, for a client no operator provisionedShow, rather than redirect, that error for a client no operator provisioned
5the sign-in is too old for what is asked: the person signs in againSend the person to sign in
6no consent covers the request: the person is askedSend the person to consent
7the sign-in is fresh enough and a consent covers the requestMint the authorization code under the consent and the session

The first matching rule wins.

Exact conditions
#ConditionGoes toSituations
1silent and needsFreshLogin and operatorClientlogin_required.fresh_login432 of 2196
2silent and needsFreshLoginlogin_required.fresh_login_shown432 of 2196
3silent and consentMissing and operatorClientconsent_required.prompt_none216 of 2196
4silent and consentMissingconsent_required.prompt_none_shown216 of 2196
5needsFreshLoginsignInNeeded180 of 2196
6consentMissingconsentNeeded126 of 2196
7otherwisemintingCode594 of 2196
operatorClient
provisioning == 'operator'
silent
promptNone
needsFreshLogin
stepUp == 'freshLogin'
consentMissing
consent == 'missing'

Send the person to sign in

#IfThen
1the request is decided at the finish of an interaction: the next interaction continues itContinue the request in a new sign-in interaction
2INTERACTION_UI_ENABLED is offPark the authorization request for the sign-in
3INTERACTION_UI_ENABLED is onStart a sign-in interaction

The first matching rule wins.

Exact conditions
#ConditionGoes toSituations
1finishingcontinuingToSignIn244 of 1420
2pagesparkingRequest588 of 1420
3otherwisestartingSignIn588 of 1420
pages
mode == 'pages'
finishing
phase == 'finish'

Send the person to consent

#IfThen
1INTERACTION_UI_ENABLED is off, and the consent was revoked under the requestSend the user whose consent was revoked under the request to the consent page
2INTERACTION_UI_ENABLED is offSend the signed-in user to the consent page
3the consent step cannot show the scopes, decided when the interaction finishedTell the client the consent step cannot show its scopes, once the person signed in
4the consent step cannot show the resources, decided when the interaction finishedTell the client the consent step cannot show its resources, once the person signed in
5the consent step cannot show the scopes, for a client an operator provisionedTell the client the consent step cannot show its scopes
6the consent step cannot show the scopes, for a client no operator provisionedShow, rather than redirect, that error for a client no operator provisioned
7the consent step cannot show the resources, for a client an operator provisionedTell the client the consent step cannot show its resources
8the consent step cannot show the resources, for a client no operator provisionedShow, rather than redirect, that error for a client no operator provisioned
9the consent step can show the request, which an interaction just finished: the next one continues itContinue the request in a consent interaction
10the consent step can show the requestStart a consent interaction

The first matching rule wins.

Exact conditions
#ConditionGoes toSituations
1pages and consentCause == 'withdrawn'consent_screen.consent_withdrawn36 of 288
2pagesconsent_screen.page36 of 288
3scopesUnshowable and finishinginvalid_scope.consent_not_shown_after_sign_in48 of 288
4resourcesUnshowable and finishinginvalid_target.consent_not_shown_after_sign_in48 of 288
5scopesUnshowable and operatorClientinvalid_scope.consent_not_shown12 of 288
6scopesUnshowableinvalid_scope.consent_not_shown_shown12 of 288
7resourcesUnshowable and operatorClientinvalid_target.consent_not_shown12 of 288
8resourcesUnshowableinvalid_target.consent_not_shown_shown12 of 288
9finishingcontinuingToConsent48 of 288
10otherwisestartingConsent24 of 288
operatorClient
provisioning == 'operator'
scopesUnshowable
refusal == 'unshowableScopes'
resourcesUnshowable
refusal == 'unshowableResources'
pages
mode == 'pages'
finishing
phase == 'finish'

Check the request again before the cancel goes to the client

#IfThen
1the client, or its redirect URI, no longer passesRefuse a finish or a cancel whose client or redirect URI no longer passes
2the client may no longer use the endpointRefuse a finish or a cancel whose client may no longer use the endpoint
3the request still passesTell the client the person cancelled

The first matching rule wins.

Exact conditions
#ConditionGoes toSituations
1since == 'clientGone'invalid_request.client_changed444 of 1624
2since == 'clientUnusable'unauthorized_client.client_changed444 of 1624
3otherwiseaccess_denied.cancelled736 of 1624

Check the request again, as the endpoint checks it

#IfThen
1the client, or its redirect URI, no longer passesRefuse a finish or a cancel whose client or redirect URI no longer passes
2the client may no longer use the endpointRefuse a finish or a cancel whose client may no longer use the endpoint
3the request still passesFind the session the interaction holds

The first matching rule wins.

Exact conditions
#ConditionGoes toSituations
1since == 'clientGone'invalid_request.client_changed356 of 1240
2since == 'clientUnusable'unauthorized_client.client_changed356 of 1240
3otherwisefindingTransactionSession528 of 1240

Find the session the interaction holds

#IfThen
1the session is no longer usable: the request needs a sign-in againSend the person to sign in
2the session is live: the request is decided again for itRefuse an agent scope above the client's cap

The first matching rule wins.

Exact conditions
#ConditionGoes toSituations
1finishSession == 'unusable'signInNeeded284 of 528
2otherwisecheckingAgentCap244 of 528

Every way it can end

It ends withWhenWhat happens
Send the authorization code to the client
redirect with code + state + iss
INTERACTION_UI_ENABLED is off, the default: the sign-in and the consent are the server-rendered pages, the host is the primary host of an enabled realm, the address is under its limit, the parameters pass the route schema, and the client, its redirect URI, its grant and response type and dpop_jkt all pass, an operator provisioned the client (provisioned_by_operator): the system client or the seed manifest, the request carries the cookie of a live browser session of an enabled user, nothing in the request is refused after the session, it carries no prompt, or prompt=login, prompt=consent or prompt=create, the request carries no prompt=create, nothing asks for a fresh sign-in, or the sign-in is fresh enough for what asks, a stored consent covers every requested scope at each requested resource, or the client's administrative consent does (ADR-017 Decision 9), and nothing asks for the screen, the client and its redirect URI still pass when the interaction finishes or is cancelled, the session the interaction holds is live and its account may use it, when the request is decided again
  1. Wait for an authorization request: GET /oauth/authorize arrives with its parameters in the query, or POST with them in a form
  2. Find the realm of the host: the request has its realm
  3. Count the request against the authorize limit: the address is under its limit
  4. Check the parameters against the authorize schema: the parameters match the schema
  5. Find the client: the client is found
  6. Check the redirect URI against the client's registration: redirect_uri is registered
  7. Check the redirect URI against the environment policy: the environment permits the redirect URI
  8. Check that the client may use the endpoint: the client may use the endpoint
  9. Read the DPoP key the code is to be bound to: dpop_jkt is absent, unread or well formed
  10. Check a request for a registration: the request carries no prompt=create
  11. Find the browser session: the session is live
  12. Refuse an agent scope above the client's cap: no agent scope is above the cap; the scopes are the requested ones the client's allowlist holds
  13. Refuse a QAuth API audience the client does not list: every QAuth API audience among the resources is one the client lists
  14. Read the consent, and decide whether the sign-in is fresh enough and the consent covers the request: the sign-in is fresh enough and a consent covers the request
  15. Mint the authorization code under the consent and the session: the code is stored
Send the authorization code to the client once the interaction finished
redirect with code + state + iss
INTERACTION_UI_ENABLED is on: the sign-in and the consent are interactions (#628), the host is the primary host of an enabled realm, the address is under its limit, the parameters pass the route schema, and the client, its redirect URI, its grant and response type and dpop_jkt all pass, an operator provisioned the client (provisioned_by_operator): the system client or the seed manifest, the request carries the cookie of a live browser session of an enabled user, nothing in the request is refused after the session, it carries no prompt, or prompt=login, prompt=consent or prompt=create, prompt=create with openid and no max_age, the realm and the client allowing sign-up, nothing asks for a fresh sign-in, or the sign-in is fresh enough for what asks, a stored consent covers every requested scope at each requested resource, or the client's administrative consent does (ADR-017 Decision 9), and nothing asks for the screen, the client and its redirect URI still pass when the interaction finishes or is cancelled, the session the interaction holds is live and its account may use it, when the request is decided again
  1. Wait for an authorization request: GET /oauth/authorize arrives with its parameters in the query, or POST with them in a form
  2. Find the realm of the host: the request has its realm
  3. Count the request against the authorize limit: the address is under its limit
  4. Check the parameters against the authorize schema: the parameters match the schema
  5. Find the client: the client is found
  6. Check the redirect URI against the client's registration: redirect_uri is registered
  7. Check the redirect URI against the environment policy: the environment permits the redirect URI
  8. Check that the client may use the endpoint: the client may use the endpoint
  9. Read the DPoP key the code is to be bound to: dpop_jkt is absent, unread or well formed
  10. Check a request for a registration: the registration is allowed
  11. Start a registration interaction: the interaction is stored
  12. The person registers at the ceremony page: the new password creates the account, which finishes the interaction
  13. End the interaction before anything is issued: the interaction is over
  14. Check the request again, as the endpoint checks it: the request still passes
  15. Find the session the interaction holds: the session is live: the request is decided again for it
  16. Refuse an agent scope above the client's cap: no agent scope is above the cap; the scopes are the requested ones the client's allowlist holds
  17. Refuse a QAuth API audience the client does not list: every QAuth API audience among the resources is one the client lists
  18. Read the consent, and decide whether the sign-in is fresh enough and the consent covers the request: the sign-in is fresh enough and a consent covers the request
  19. Mint the authorization code under the consent and the session: the code is stored, for the request whose interaction finished
Send a browser with no session to sign in
no redirect, page shown
INTERACTION_UI_ENABLED is off, the default: the sign-in and the consent are the server-rendered pages, the host is the primary host of an enabled realm, the address is under its limit, the parameters pass the route schema, and the client, its redirect URI, its grant and response type and dpop_jkt all pass, an operator provisioned the client (provisioned_by_operator): the system client or the seed manifest, the request carries no session cookie, or one that names a cookie key this process has not read yet and may not read again yet (#493), which is left for the next request, nothing in the request is refused after the session, it carries no prompt, or prompt=login, prompt=consent or prompt=create, the request carries no prompt=create, nothing asks for a fresh sign-in, or the sign-in is fresh enough for what asks, a stored consent covers every requested scope at each requested resource, or the client's administrative consent does (ADR-017 Decision 9), and nothing asks for the screen, the client and its redirect URI still pass when the interaction finishes or is cancelled, the session the interaction holds is live and its account may use it, when the request is decided again
  1. Wait for an authorization request: GET /oauth/authorize arrives with its parameters in the query, or POST with them in a form
  2. Find the realm of the host: the request has its realm
  3. Count the request against the authorize limit: the address is under its limit
  4. Check the parameters against the authorize schema: the parameters match the schema
  5. Find the client: the client is found
  6. Check the redirect URI against the client's registration: redirect_uri is registered
  7. Check the redirect URI against the environment policy: the environment permits the redirect URI
  8. Check that the client may use the endpoint: the client may use the endpoint
  9. Read the DPoP key the code is to be bound to: dpop_jkt is absent, unread or well formed
  10. Check a request for a registration: the request carries no prompt=create
  11. Find the browser session: no usable session: the person signs in first, and the request is decided again with that session
  12. Send the person to sign in: INTERACTION_UI_ENABLED is off
  13. Park the authorization request for the sign-in: the request is parked, for a request with no session
Send a browser whose session cookie is of no use to sign in
no redirect, page shown
INTERACTION_UI_ENABLED is off, the default: the sign-in and the consent are the server-rendered pages, the host is the primary host of an enabled realm, the address is under its limit, the parameters pass the route schema, and the client, its redirect URI, its grant and response type and dpop_jkt all pass, an operator provisioned the client (provisioned_by_operator): the system client or the seed manifest, the cookie does not verify with the realm's cookie keys, or its session has ended or expired, or its user has been deleted or disabled, or was disabled after the session began; the cookie is cleared, and a disabled user's session is ended, nothing in the request is refused after the session, it carries no prompt, or prompt=login, prompt=consent or prompt=create, the request carries no prompt=create, nothing asks for a fresh sign-in, or the sign-in is fresh enough for what asks, a stored consent covers every requested scope at each requested resource, or the client's administrative consent does (ADR-017 Decision 9), and nothing asks for the screen, the client and its redirect URI still pass when the interaction finishes or is cancelled, the session the interaction holds is live and its account may use it, when the request is decided again
  1. Wait for an authorization request: GET /oauth/authorize arrives with its parameters in the query, or POST with them in a form
  2. Find the realm of the host: the request has its realm
  3. Count the request against the authorize limit: the address is under its limit
  4. Check the parameters against the authorize schema: the parameters match the schema
  5. Find the client: the client is found
  6. Check the redirect URI against the client's registration: redirect_uri is registered
  7. Check the redirect URI against the environment policy: the environment permits the redirect URI
  8. Check that the client may use the endpoint: the client may use the endpoint
  9. Read the DPoP key the code is to be bound to: dpop_jkt is absent, unread or well formed
  10. Check a request for a registration: the request carries no prompt=create
  11. Find the browser session: no usable session: the person signs in first, and the request is decided again with that session
  12. Send the person to sign in: INTERACTION_UI_ENABLED is off
  13. Park the authorization request for the sign-in: the request is parked, for a cookie of no usable session
Send a browser whose sign-in is too old for the request to sign in again
no redirect, page shown
INTERACTION_UI_ENABLED is off, the default: the sign-in and the consent are the server-rendered pages, the host is the primary host of an enabled realm, the address is under its limit, the parameters pass the route schema, and the client, its redirect URI, its grant and response type and dpop_jkt all pass, an operator provisioned the client (provisioned_by_operator): the system client or the seed manifest, the request carries the cookie of a live browser session of an enabled user, nothing in the request is refused after the session, it carries no prompt, or prompt=login, prompt=consent or prompt=create, the request carries no prompt=create, prompt=login, a dangerous scope (write:*, agent:admin, agent:exec) outside development, or a native_backend client asks for a sign-in within the last two minutes and it is older; or max_age asks for one within that many whole seconds and it is older, a stored consent covers every requested scope at each requested resource, or the client's administrative consent does (ADR-017 Decision 9), and nothing asks for the screen, the client and its redirect URI still pass when the interaction finishes or is cancelled, the session the interaction holds is live and its account may use it, when the request is decided again
  1. Wait for an authorization request: GET /oauth/authorize arrives with its parameters in the query, or POST with them in a form
  2. Find the realm of the host: the request has its realm
  3. Count the request against the authorize limit: the address is under its limit
  4. Check the parameters against the authorize schema: the parameters match the schema
  5. Find the client: the client is found
  6. Check the redirect URI against the client's registration: redirect_uri is registered
  7. Check the redirect URI against the environment policy: the environment permits the redirect URI
  8. Check that the client may use the endpoint: the client may use the endpoint
  9. Read the DPoP key the code is to be bound to: dpop_jkt is absent, unread or well formed
  10. Check a request for a registration: the request carries no prompt=create
  11. Find the browser session: the session is live
  12. Refuse an agent scope above the client's cap: no agent scope is above the cap; the scopes are the requested ones the client's allowlist holds
  13. Refuse a QAuth API audience the client does not list: every QAuth API audience among the resources is one the client lists
  14. Read the consent, and decide whether the sign-in is fresh enough and the consent covers the request: the sign-in is too old for what is asked: the person signs in again
  15. Send the person to sign in: INTERACTION_UI_ENABLED is off
  16. Park the authorization request for the sign-in: the request is parked, for a step-up
Send a browser whose session ended under the request to sign in again
no redirect, page shown
INTERACTION_UI_ENABLED is off, the default: the sign-in and the consent are the server-rendered pages, the host is the primary host of an enabled realm, the address is under its limit, the parameters pass the route schema, and the client, its redirect URI, its grant and response type and dpop_jkt all pass, an operator provisioned the client (provisioned_by_operator): the system client or the seed manifest, the request carries the cookie of a live browser session of an enabled user, nothing in the request is refused after the session, it carries no prompt, or prompt=login, prompt=consent or prompt=create, the request carries no prompt=create, nothing asks for a fresh sign-in, or the sign-in is fresh enough for what asks, a stored consent covers every requested scope at each requested resource, or the client's administrative consent does (ADR-017 Decision 9), and nothing asks for the screen, the client and its redirect URI still pass when the interaction finishes or is cancelled, the session the interaction holds is live and its account may use it, when the request is decided again
  1. Wait for an authorization request: GET /oauth/authorize arrives with its parameters in the query, or POST with them in a form
  2. Find the realm of the host: the request has its realm
  3. Count the request against the authorize limit: the address is under its limit
  4. Check the parameters against the authorize schema: the parameters match the schema
  5. Find the client: the client is found
  6. Check the redirect URI against the client's registration: redirect_uri is registered
  7. Check the redirect URI against the environment policy: the environment permits the redirect URI
  8. Check that the client may use the endpoint: the client may use the endpoint
  9. Read the DPoP key the code is to be bound to: dpop_jkt is absent, unread or well formed
  10. Check a request for a registration: the request carries no prompt=create
  11. Find the browser session: the session is live
  12. Refuse an agent scope above the client's cap: no agent scope is above the cap; the scopes are the requested ones the client's allowlist holds
  13. Refuse a QAuth API audience the client does not list: every QAuth API audience among the resources is one the client lists
  14. Read the consent, and decide whether the sign-in is fresh enough and the consent covers the request: the sign-in is fresh enough and a consent covers the request
  15. Mint the authorization code under the consent and the session: it fails, because the session ended under the request: the person signs in again
  16. Send the person to sign in: INTERACTION_UI_ENABLED is off
  17. Park the authorization request for the sign-in: the request is parked, for a session that ended under it
Send the signed-in user to the consent page
no redirect, page shown
INTERACTION_UI_ENABLED is off, the default: the sign-in and the consent are the server-rendered pages, the host is the primary host of an enabled realm, the address is under its limit, the parameters pass the route schema, and the client, its redirect URI, its grant and response type and dpop_jkt all pass, an operator provisioned the client (provisioned_by_operator): the system client or the seed manifest, the request carries the cookie of a live browser session of an enabled user, nothing in the request is refused after the session, it carries no prompt, or prompt=login, prompt=consent or prompt=create, the request carries no prompt=create, nothing asks for a fresh sign-in, or the sign-in is fresh enough for what asks, no stored consent covers the request, prompt=consent asks for the screen, the request widens a prior grant, or the client is an AI agent, which never skips the screen (ADR-015 Decision 11), the client and its redirect URI still pass when the interaction finishes or is cancelled, the session the interaction holds is live and its account may use it, when the request is decided again
  1. Wait for an authorization request: GET /oauth/authorize arrives with its parameters in the query, or POST with them in a form
  2. Find the realm of the host: the request has its realm
  3. Count the request against the authorize limit: the address is under its limit
  4. Check the parameters against the authorize schema: the parameters match the schema
  5. Find the client: the client is found
  6. Check the redirect URI against the client's registration: redirect_uri is registered
  7. Check the redirect URI against the environment policy: the environment permits the redirect URI
  8. Check that the client may use the endpoint: the client may use the endpoint
  9. Read the DPoP key the code is to be bound to: dpop_jkt is absent, unread or well formed
  10. Check a request for a registration: the request carries no prompt=create
  11. Find the browser session: the session is live
  12. Refuse an agent scope above the client's cap: no agent scope is above the cap; the scopes are the requested ones the client's allowlist holds
  13. Refuse a QAuth API audience the client does not list: every QAuth API audience among the resources is one the client lists
  14. Read the consent, and decide whether the sign-in is fresh enough and the consent covers the request: no consent covers the request: the person is asked
  15. Send the person to consent: INTERACTION_UI_ENABLED is off
Send the user whose consent was revoked under the request to the consent page
no redirect, page shown
INTERACTION_UI_ENABLED is off, the default: the sign-in and the consent are the server-rendered pages, the host is the primary host of an enabled realm, the address is under its limit, the parameters pass the route schema, and the client, its redirect URI, its grant and response type and dpop_jkt all pass, an operator provisioned the client (provisioned_by_operator): the system client or the seed manifest, the request carries the cookie of a live browser session of an enabled user, nothing in the request is refused after the session, it carries no prompt, or prompt=login, prompt=consent or prompt=create, the request carries no prompt=create, nothing asks for a fresh sign-in, or the sign-in is fresh enough for what asks, a stored consent covers every requested scope at each requested resource, or the client's administrative consent does (ADR-017 Decision 9), and nothing asks for the screen, the client and its redirect URI still pass when the interaction finishes or is cancelled, the session the interaction holds is live and its account may use it, when the request is decided again
  1. Wait for an authorization request: GET /oauth/authorize arrives with its parameters in the query, or POST with them in a form
  2. Find the realm of the host: the request has its realm
  3. Count the request against the authorize limit: the address is under its limit
  4. Check the parameters against the authorize schema: the parameters match the schema
  5. Find the client: the client is found
  6. Check the redirect URI against the client's registration: redirect_uri is registered
  7. Check the redirect URI against the environment policy: the environment permits the redirect URI
  8. Check that the client may use the endpoint: the client may use the endpoint
  9. Read the DPoP key the code is to be bound to: dpop_jkt is absent, unread or well formed
  10. Check a request for a registration: the request carries no prompt=create
  11. Find the browser session: the session is live
  12. Refuse an agent scope above the client's cap: no agent scope is above the cap; the scopes are the requested ones the client's allowlist holds
  13. Refuse a QAuth API audience the client does not list: every QAuth API audience among the resources is one the client lists
  14. Read the consent, and decide whether the sign-in is fresh enough and the consent covers the request: the sign-in is fresh enough and a consent covers the request
  15. Mint the authorization code under the consent and the session: it fails, because the consent was revoked under the request: the person is asked again
  16. Send the person to consent: INTERACTION_UI_ENABLED is off, and the consent was revoked under the request
Tell the client the person cancelled
redirect, error=access_denied
INTERACTION_UI_ENABLED is on: the sign-in and the consent are interactions (#628), the host is the primary host of an enabled realm, the address is under its limit, the parameters pass the route schema, and the client, its redirect URI, its grant and response type and dpop_jkt all pass, an operator provisioned the client (provisioned_by_operator): the system client or the seed manifest, the request carries the cookie of a live browser session of an enabled user, nothing in the request is refused after the session, it carries no prompt, or prompt=login, prompt=consent or prompt=create, prompt=create with openid and no max_age, the realm and the client allowing sign-up, nothing asks for a fresh sign-in, or the sign-in is fresh enough for what asks, a stored consent covers every requested scope at each requested resource, or the client's administrative consent does (ADR-017 Decision 9), and nothing asks for the screen, the client and its redirect URI still pass when the interaction finishes or is cancelled, the session the interaction holds is live and its account may use it, when the request is decided again
  1. Wait for an authorization request: GET /oauth/authorize arrives with its parameters in the query, or POST with them in a form
  2. Find the realm of the host: the request has its realm
  3. Count the request against the authorize limit: the address is under its limit
  4. Check the parameters against the authorize schema: the parameters match the schema
  5. Find the client: the client is found
  6. Check the redirect URI against the client's registration: redirect_uri is registered
  7. Check the redirect URI against the environment policy: the environment permits the redirect URI
  8. Check that the client may use the endpoint: the client may use the endpoint
  9. Read the DPoP key the code is to be bound to: dpop_jkt is absent, unread or well formed
  10. Check a request for a registration: the registration is allowed
  11. Start a registration interaction: the interaction is stored
  12. The person registers at the ceremony page: the person cancels, with the CSRF value of the step they see; the interaction ends
  13. Check the request again before the cancel goes to the client: the request still passes
Leave the answer to the consent step's graph
ends here
INTERACTION_UI_ENABLED is on: the sign-in and the consent are interactions (#628), the host is the primary host of an enabled realm, the address is under its limit, the parameters pass the route schema, and the client, its redirect URI, its grant and response type and dpop_jkt all pass, an operator provisioned the client (provisioned_by_operator): the system client or the seed manifest, the request carries the cookie of a live browser session of an enabled user, nothing in the request is refused after the session, it carries no prompt, or prompt=login, prompt=consent or prompt=create, the request carries no prompt=create, nothing asks for a fresh sign-in, or the sign-in is fresh enough for what asks, no stored consent covers the request, prompt=consent asks for the screen, the request widens a prior grant, or the client is an AI agent, which never skips the screen (ADR-015 Decision 11), the client and its redirect URI still pass when the interaction finishes or is cancelled, the session the interaction holds is live and its account may use it, when the request is decided again
  1. Wait for an authorization request: GET /oauth/authorize arrives with its parameters in the query, or POST with them in a form
  2. Find the realm of the host: the request has its realm
  3. Count the request against the authorize limit: the address is under its limit
  4. Check the parameters against the authorize schema: the parameters match the schema
  5. Find the client: the client is found
  6. Check the redirect URI against the client's registration: redirect_uri is registered
  7. Check the redirect URI against the environment policy: the environment permits the redirect URI
  8. Check that the client may use the endpoint: the client may use the endpoint
  9. Read the DPoP key the code is to be bound to: dpop_jkt is absent, unread or well formed
  10. Check a request for a registration: the request carries no prompt=create
  11. Find the browser session: the session is live
  12. Refuse an agent scope above the client's cap: no agent scope is above the cap; the scopes are the requested ones the client's allowlist holds
  13. Refuse a QAuth API audience the client does not list: every QAuth API audience among the resources is one the client lists
  14. Read the consent, and decide whether the sign-in is fresh enough and the consent covers the request: no consent covers the request: the person is asked
  15. Send the person to consent: the consent step can show the request
  16. Start a consent interaction: the interaction is stored
  17. The person is asked for consent at the ceremony page: the person answers the consent step
Refuse a request for an interaction that already finished
no redirect, page shown
INTERACTION_UI_ENABLED is off, the default: the sign-in and the consent are the server-rendered pages, the host is the primary host of an enabled realm, the address is under its limit, the parameters pass the route schema, and the client, its redirect URI, its grant and response type and dpop_jkt all pass, an operator provisioned the client (provisioned_by_operator): the system client or the seed manifest, the request carries the cookie of a live browser session of an enabled user, nothing in the request is refused after the session, it carries no prompt, or prompt=login, prompt=consent or prompt=create, the request carries no prompt=create, nothing asks for a fresh sign-in, or the sign-in is fresh enough for what asks, a stored consent covers every requested scope at each requested resource, or the client's administrative consent does (ADR-017 Decision 9), and nothing asks for the screen, the client and its redirect URI still pass when the interaction finishes or is cancelled, the session the interaction holds is live and its account may use it, when the request is decided again
  1. Wait for an authorization request: an answer, a cancel or a read names an interaction of this request that already finished, such as a replayed or a second form post
Refuse a finish the expiry sweep beat
no redirect, page shown
INTERACTION_UI_ENABLED is on: the sign-in and the consent are interactions (#628), the host is the primary host of an enabled realm, the address is under its limit, the parameters pass the route schema, and the client, its redirect URI, its grant and response type and dpop_jkt all pass, an operator provisioned the client (provisioned_by_operator): the system client or the seed manifest, the request carries the cookie of a live browser session of an enabled user, nothing in the request is refused after the session, it carries no prompt, or prompt=login, prompt=consent or prompt=create, prompt=create with openid and no max_age, the realm and the client allowing sign-up, nothing asks for a fresh sign-in, or the sign-in is fresh enough for what asks, a stored consent covers every requested scope at each requested resource, or the client's administrative consent does (ADR-017 Decision 9), and nothing asks for the screen, the client and its redirect URI still pass when the interaction finishes or is cancelled, the session the interaction holds is live and its account may use it, when the request is decided again
  1. Wait for an authorization request: GET /oauth/authorize arrives with its parameters in the query, or POST with them in a form
  2. Find the realm of the host: the request has its realm
  3. Count the request against the authorize limit: the address is under its limit
  4. Check the parameters against the authorize schema: the parameters match the schema
  5. Find the client: the client is found
  6. Check the redirect URI against the client's registration: redirect_uri is registered
  7. Check the redirect URI against the environment policy: the environment permits the redirect URI
  8. Check that the client may use the endpoint: the client may use the endpoint
  9. Read the DPoP key the code is to be bound to: dpop_jkt is absent, unread or well formed
  10. Check a request for a registration: the registration is allowed
  11. Start a registration interaction: the interaction is stored
  12. The person registers at the ceremony page: the new password creates the account, which finishes the interaction
  13. End the interaction before anything is issued: it fails, because the expiry sweep claimed the interaction first
Refuse a finish whose session ended since
no redirect, page shown
INTERACTION_UI_ENABLED is on: the sign-in and the consent are interactions (#628), the host is the primary host of an enabled realm, the address is under its limit, the parameters pass the route schema, and the client, its redirect URI, its grant and response type and dpop_jkt all pass, an operator provisioned the client (provisioned_by_operator): the system client or the seed manifest, the request carries the cookie of a live browser session of an enabled user, nothing in the request is refused after the session, it carries no prompt, or prompt=login, prompt=consent or prompt=create, prompt=create with openid and no max_age, the realm and the client allowing sign-up, nothing asks for a fresh sign-in, or the sign-in is fresh enough for what asks, a stored consent covers every requested scope at each requested resource, or the client's administrative consent does (ADR-017 Decision 9), and nothing asks for the screen, the client and its redirect URI still pass when the interaction finishes or is cancelled, the session the interaction holds is live and its account may use it, when the request is decided again
  1. Wait for an authorization request: GET /oauth/authorize arrives with its parameters in the query, or POST with them in a form
  2. Find the realm of the host: the request has its realm
  3. Count the request against the authorize limit: the address is under its limit
  4. Check the parameters against the authorize schema: the parameters match the schema
  5. Find the client: the client is found
  6. Check the redirect URI against the client's registration: redirect_uri is registered
  7. Check the redirect URI against the environment policy: the environment permits the redirect URI
  8. Check that the client may use the endpoint: the client may use the endpoint
  9. Read the DPoP key the code is to be bound to: dpop_jkt is absent, unread or well formed
  10. Check a request for a registration: the registration is allowed
  11. Start a registration interaction: the interaction is stored
  12. The person registers at the ceremony page: the new password creates the account, which finishes the interaction
  13. End the interaction before anything is issued: it fails, because the session the sign-in started has ended since, such as by a sign-out in another tab
Refuse a finish or a cancel whose client or redirect URI no longer passes
no redirect, page shown
INTERACTION_UI_ENABLED is on: the sign-in and the consent are interactions (#628), the host is the primary host of an enabled realm, the address is under its limit, the parameters pass the route schema, and the client, its redirect URI, its grant and response type and dpop_jkt all pass, an operator provisioned the client (provisioned_by_operator): the system client or the seed manifest, the request carries the cookie of a live browser session of an enabled user, nothing in the request is refused after the session, it carries no prompt, or prompt=login, prompt=consent or prompt=create, prompt=create with openid and no max_age, the realm and the client allowing sign-up, nothing asks for a fresh sign-in, or the sign-in is fresh enough for what asks, a stored consent covers every requested scope at each requested resource, or the client's administrative consent does (ADR-017 Decision 9), and nothing asks for the screen, by the finish or the cancel, client_id names no client any more, or its redirect URI was removed or is no longer permitted, the session the interaction holds is live and its account may use it, when the request is decided again
  1. Wait for an authorization request: GET /oauth/authorize arrives with its parameters in the query, or POST with them in a form
  2. Find the realm of the host: the request has its realm
  3. Count the request against the authorize limit: the address is under its limit
  4. Check the parameters against the authorize schema: the parameters match the schema
  5. Find the client: the client is found
  6. Check the redirect URI against the client's registration: redirect_uri is registered
  7. Check the redirect URI against the environment policy: the environment permits the redirect URI
  8. Check that the client may use the endpoint: the client may use the endpoint
  9. Read the DPoP key the code is to be bound to: dpop_jkt is absent, unread or well formed
  10. Check a request for a registration: the registration is allowed
  11. Start a registration interaction: the interaction is stored
  12. The person registers at the ceremony page: the person cancels, with the CSRF value of the step they see; the interaction ends
  13. Check the request again before the cancel goes to the client: the client, or its redirect URI, no longer passes
Refuse a finish or a cancel whose client may no longer use the endpoint
no redirect, page shown
INTERACTION_UI_ENABLED is on: the sign-in and the consent are interactions (#628), the host is the primary host of an enabled realm, the address is under its limit, the parameters pass the route schema, and the client, its redirect URI, its grant and response type and dpop_jkt all pass, an operator provisioned the client (provisioned_by_operator): the system client or the seed manifest, the request carries the cookie of a live browser session of an enabled user, nothing in the request is refused after the session, it carries no prompt, or prompt=login, prompt=consent or prompt=create, prompt=create with openid and no max_age, the realm and the client allowing sign-up, nothing asks for a fresh sign-in, or the sign-in is fresh enough for what asks, a stored consent covers every requested scope at each requested resource, or the client's administrative consent does (ADR-017 Decision 9), and nothing asks for the screen, by the finish or the cancel, the client was disabled or suspended, or lost the authorization_code grant or the code response type, the session the interaction holds is live and its account may use it, when the request is decided again
  1. Wait for an authorization request: GET /oauth/authorize arrives with its parameters in the query, or POST with them in a form
  2. Find the realm of the host: the request has its realm
  3. Count the request against the authorize limit: the address is under its limit
  4. Check the parameters against the authorize schema: the parameters match the schema
  5. Find the client: the client is found
  6. Check the redirect URI against the client's registration: redirect_uri is registered
  7. Check the redirect URI against the environment policy: the environment permits the redirect URI
  8. Check that the client may use the endpoint: the client may use the endpoint
  9. Read the DPoP key the code is to be bound to: dpop_jkt is absent, unread or well formed
  10. Check a request for a registration: the registration is allowed
  11. Start a registration interaction: the interaction is stored
  12. The person registers at the ceremony page: the person cancels, with the CSRF value of the step they see; the interaction ends
  13. Check the request again before the cancel goes to the client: the client may no longer use the endpoint
Refuse a next interaction too large to hold
no redirect, page shown
INTERACTION_UI_ENABLED is on: the sign-in and the consent are interactions (#628), the host is the primary host of an enabled realm, the address is under its limit, the parameters pass the route schema, and the client, its redirect URI, its grant and response type and dpop_jkt all pass, an operator provisioned the client (provisioned_by_operator): the system client or the seed manifest, the request carries the cookie of a live browser session of an enabled user, nothing in the request is refused after the session, it carries no prompt, or prompt=login, prompt=consent or prompt=create, prompt=create with openid and no max_age, the realm and the client allowing sign-up, nothing asks for a fresh sign-in, or the sign-in is fresh enough for what asks, a stored consent covers every requested scope at each requested resource, or the client's administrative consent does (ADR-017 Decision 9), and nothing asks for the screen, the client and its redirect URI still pass when the interaction finishes or is cancelled, it ended, or its account was disabled, between the interaction's finish and the decision: the request needs a sign-in again
  1. Wait for an authorization request: GET /oauth/authorize arrives with its parameters in the query, or POST with them in a form
  2. Find the realm of the host: the request has its realm
  3. Count the request against the authorize limit: the address is under its limit
  4. Check the parameters against the authorize schema: the parameters match the schema
  5. Find the client: the client is found
  6. Check the redirect URI against the client's registration: redirect_uri is registered
  7. Check the redirect URI against the environment policy: the environment permits the redirect URI
  8. Check that the client may use the endpoint: the client may use the endpoint
  9. Read the DPoP key the code is to be bound to: dpop_jkt is absent, unread or well formed
  10. Check a request for a registration: the registration is allowed
  11. Start a registration interaction: the interaction is stored
  12. The person registers at the ceremony page: the new password creates the account, which finishes the interaction
  13. End the interaction before anything is issued: the interaction is over
  14. Check the request again, as the endpoint checks it: the request still passes
  15. Find the session the interaction holds: the session is no longer usable: the request needs a sign-in again
  16. Send the person to sign in: the request is decided at the finish of an interaction: the next interaction continues it
  17. Continue the request in a new sign-in interaction: it fails, because the record of the next interaction is over 32 KiB
Fail the answer when the interaction store fails
no redirect, page shown
INTERACTION_UI_ENABLED is on: the sign-in and the consent are interactions (#628), the host is the primary host of an enabled realm, the address is under its limit, the parameters pass the route schema, and the client, its redirect URI, its grant and response type and dpop_jkt all pass, an operator provisioned the client (provisioned_by_operator): the system client or the seed manifest, the request carries the cookie of a live browser session of an enabled user, nothing in the request is refused after the session, it carries no prompt, or prompt=login, prompt=consent or prompt=create, prompt=create with openid and no max_age, the realm and the client allowing sign-up, nothing asks for a fresh sign-in, or the sign-in is fresh enough for what asks, a stored consent covers every requested scope at each requested resource, or the client's administrative consent does (ADR-017 Decision 9), and nothing asks for the screen, the client and its redirect URI still pass when the interaction finishes or is cancelled, the session the interaction holds is live and its account may use it, when the request is decided again
  1. Wait for an authorization request: GET /oauth/authorize arrives with its parameters in the query, or POST with them in a form
  2. Find the realm of the host: the request has its realm
  3. Count the request against the authorize limit: the address is under its limit
  4. Check the parameters against the authorize schema: the parameters match the schema
  5. Find the client: the client is found
  6. Check the redirect URI against the client's registration: redirect_uri is registered
  7. Check the redirect URI against the environment policy: the environment permits the redirect URI
  8. Check that the client may use the endpoint: the client may use the endpoint
  9. Read the DPoP key the code is to be bound to: dpop_jkt is absent, unread or well formed
  10. Check a request for a registration: the registration is allowed
  11. Start a registration interaction: the interaction is stored
  12. The person registers at the ceremony page: the new password creates the account, which finishes the interaction
  13. End the interaction before anything is issued: it fails, because the interaction store fails; the turn is given back
Fail the answer when the database fails at the mint
no redirect, page shown
INTERACTION_UI_ENABLED is on: the sign-in and the consent are interactions (#628), the host is the primary host of an enabled realm, the address is under its limit, the parameters pass the route schema, and the client, its redirect URI, its grant and response type and dpop_jkt all pass, an operator provisioned the client (provisioned_by_operator): the system client or the seed manifest, the request carries the cookie of a live browser session of an enabled user, nothing in the request is refused after the session, it carries no prompt, or prompt=login, prompt=consent or prompt=create, prompt=create with openid and no max_age, the realm and the client allowing sign-up, nothing asks for a fresh sign-in, or the sign-in is fresh enough for what asks, a stored consent covers every requested scope at each requested resource, or the client's administrative consent does (ADR-017 Decision 9), and nothing asks for the screen, the client and its redirect URI still pass when the interaction finishes or is cancelled, the session the interaction holds is live and its account may use it, when the request is decided again
  1. Wait for an authorization request: GET /oauth/authorize arrives with its parameters in the query, or POST with them in a form
  2. Find the realm of the host: the request has its realm
  3. Count the request against the authorize limit: the address is under its limit
  4. Check the parameters against the authorize schema: the parameters match the schema
  5. Find the client: the client is found
  6. Check the redirect URI against the client's registration: redirect_uri is registered
  7. Check the redirect URI against the environment policy: the environment permits the redirect URI
  8. Check that the client may use the endpoint: the client may use the endpoint
  9. Read the DPoP key the code is to be bound to: dpop_jkt is absent, unread or well formed
  10. Check a request for a registration: the registration is allowed
  11. Start a registration interaction: the interaction is stored
  12. The person registers at the ceremony page: the new password creates the account, which finishes the interaction
  13. End the interaction before anything is issued: the interaction is over
  14. Check the request again, as the endpoint checks it: the request still passes
  15. Find the session the interaction holds: the session is live: the request is decided again for it
  16. Refuse an agent scope above the client's cap: no agent scope is above the cap; the scopes are the requested ones the client's allowlist holds
  17. Refuse a QAuth API audience the client does not list: every QAuth API audience among the resources is one the client lists
  18. Read the consent, and decide whether the sign-in is fresh enough and the consent covers the request: the sign-in is fresh enough and a consent covers the request
  19. Mint the authorization code under the consent and the session: it fails, because the database fails, when the interaction finished
Tell the client an agent scope is above its cap, once the person signed in
redirect, error=invalid_scope
INTERACTION_UI_ENABLED is on: the sign-in and the consent are interactions (#628), the host is the primary host of an enabled realm, the address is under its limit, the parameters pass the route schema, and the client, its redirect URI, its grant and response type and dpop_jkt all pass, an operator provisioned the client (provisioned_by_operator): the system client or the seed manifest, the request carries the cookie of a live browser session of an enabled user, the scope parameter names an agent:* scope above the client's agent mode cap (any agent:* scope for a client that is no agent or has no cap), it carries no prompt, or prompt=login, prompt=consent or prompt=create, prompt=create with openid and no max_age, the realm and the client allowing sign-up, nothing asks for a fresh sign-in, or the sign-in is fresh enough for what asks, a stored consent covers every requested scope at each requested resource, or the client's administrative consent does (ADR-017 Decision 9), and nothing asks for the screen, the client and its redirect URI still pass when the interaction finishes or is cancelled, the session the interaction holds is live and its account may use it, when the request is decided again
  1. Wait for an authorization request: GET /oauth/authorize arrives with its parameters in the query, or POST with them in a form
  2. Find the realm of the host: the request has its realm
  3. Count the request against the authorize limit: the address is under its limit
  4. Check the parameters against the authorize schema: the parameters match the schema
  5. Find the client: the client is found
  6. Check the redirect URI against the client's registration: redirect_uri is registered
  7. Check the redirect URI against the environment policy: the environment permits the redirect URI
  8. Check that the client may use the endpoint: the client may use the endpoint
  9. Read the DPoP key the code is to be bound to: dpop_jkt is absent, unread or well formed
  10. Check a request for a registration: the registration is allowed
  11. Start a registration interaction: the interaction is stored
  12. The person registers at the ceremony page: the new password creates the account, which finishes the interaction
  13. End the interaction before anything is issued: the interaction is over
  14. Check the request again, as the endpoint checks it: the request still passes
  15. Find the session the interaction holds: the session is live: the request is decided again for it
  16. Refuse an agent scope above the client's cap: an agent scope is above the cap, decided when the interaction finished
Tell the client it named an audience it does not list, once the person signed in
redirect, error=invalid_target
INTERACTION_UI_ENABLED is on: the sign-in and the consent are interactions (#628), the host is the primary host of an enabled realm, the address is under its limit, the parameters pass the route schema, and the client, its redirect URI, its grant and response type and dpop_jkt all pass, an operator provisioned the client (provisioned_by_operator): the system client or the seed manifest, the request carries the cookie of a live browser session of an enabled user, a resource indicator names a QAuth API audience (urn:qauth:aud:) the client does not list, it carries no prompt, or prompt=login, prompt=consent or prompt=create, prompt=create with openid and no max_age, the realm and the client allowing sign-up, nothing asks for a fresh sign-in, or the sign-in is fresh enough for what asks, a stored consent covers every requested scope at each requested resource, or the client's administrative consent does (ADR-017 Decision 9), and nothing asks for the screen, the client and its redirect URI still pass when the interaction finishes or is cancelled, the session the interaction holds is live and its account may use it, when the request is decided again
  1. Wait for an authorization request: GET /oauth/authorize arrives with its parameters in the query, or POST with them in a form
  2. Find the realm of the host: the request has its realm
  3. Count the request against the authorize limit: the address is under its limit
  4. Check the parameters against the authorize schema: the parameters match the schema
  5. Find the client: the client is found
  6. Check the redirect URI against the client's registration: redirect_uri is registered
  7. Check the redirect URI against the environment policy: the environment permits the redirect URI
  8. Check that the client may use the endpoint: the client may use the endpoint
  9. Read the DPoP key the code is to be bound to: dpop_jkt is absent, unread or well formed
  10. Check a request for a registration: the registration is allowed
  11. Start a registration interaction: the interaction is stored
  12. The person registers at the ceremony page: the new password creates the account, which finishes the interaction
  13. End the interaction before anything is issued: the interaction is over
  14. Check the request again, as the endpoint checks it: the request still passes
  15. Find the session the interaction holds: the session is live: the request is decided again for it
  16. Refuse an agent scope above the client's cap: no agent scope is above the cap; the scopes are the requested ones the client's allowlist holds
  17. Refuse a QAuth API audience the client does not list: a resource names a QAuth API audience the client does not list, decided when the interaction finished
Tell the client the consent step cannot show its scopes, once the person signed in
redirect, error=invalid_scope
INTERACTION_UI_ENABLED is on: the sign-in and the consent are interactions (#628), the host is the primary host of an enabled realm, the address is under its limit, the parameters pass the route schema, and the client, its redirect URI, its grant and response type and dpop_jkt all pass, an operator provisioned the client (provisioned_by_operator): the system client or the seed manifest, the request carries the cookie of a live browser session of an enabled user, the consent step cannot show the scopes: more than 64, or one outside its alphabet (RFC 6749 §3.3 without < and >) or over 128 characters; read only when an interaction asks for consent, it carries no prompt, or prompt=login, prompt=consent or prompt=create, prompt=create with openid and no max_age, the realm and the client allowing sign-up, nothing asks for a fresh sign-in, or the sign-in is fresh enough for what asks, no stored consent covers the request, prompt=consent asks for the screen, the request widens a prior grant, or the client is an AI agent, which never skips the screen (ADR-015 Decision 11), the client and its redirect URI still pass when the interaction finishes or is cancelled, the session the interaction holds is live and its account may use it, when the request is decided again
  1. Wait for an authorization request: GET /oauth/authorize arrives with its parameters in the query, or POST with them in a form
  2. Find the realm of the host: the request has its realm
  3. Count the request against the authorize limit: the address is under its limit
  4. Check the parameters against the authorize schema: the parameters match the schema
  5. Find the client: the client is found
  6. Check the redirect URI against the client's registration: redirect_uri is registered
  7. Check the redirect URI against the environment policy: the environment permits the redirect URI
  8. Check that the client may use the endpoint: the client may use the endpoint
  9. Read the DPoP key the code is to be bound to: dpop_jkt is absent, unread or well formed
  10. Check a request for a registration: the registration is allowed
  11. Start a registration interaction: the interaction is stored
  12. The person registers at the ceremony page: the new password creates the account, which finishes the interaction
  13. End the interaction before anything is issued: the interaction is over
  14. Check the request again, as the endpoint checks it: the request still passes
  15. Find the session the interaction holds: the session is live: the request is decided again for it
  16. Refuse an agent scope above the client's cap: no agent scope is above the cap; the scopes are the requested ones the client's allowlist holds
  17. Refuse a QAuth API audience the client does not list: every QAuth API audience among the resources is one the client lists
  18. Read the consent, and decide whether the sign-in is fresh enough and the consent covers the request: no consent covers the request: the person is asked
  19. Send the person to consent: the consent step cannot show the scopes, decided when the interaction finished
Tell the client the consent step cannot show its resources, once the person signed in
redirect, error=invalid_target
INTERACTION_UI_ENABLED is on: the sign-in and the consent are interactions (#628), the host is the primary host of an enabled realm, the address is under its limit, the parameters pass the route schema, and the client, its redirect URI, its grant and response type and dpop_jkt all pass, an operator provisioned the client (provisioned_by_operator): the system client or the seed manifest, the request carries the cookie of a live browser session of an enabled user, the consent step cannot show the resources: more than 16, or one over 2048 characters; read only when an interaction asks for consent, it carries no prompt, or prompt=login, prompt=consent or prompt=create, prompt=create with openid and no max_age, the realm and the client allowing sign-up, nothing asks for a fresh sign-in, or the sign-in is fresh enough for what asks, no stored consent covers the request, prompt=consent asks for the screen, the request widens a prior grant, or the client is an AI agent, which never skips the screen (ADR-015 Decision 11), the client and its redirect URI still pass when the interaction finishes or is cancelled, the session the interaction holds is live and its account may use it, when the request is decided again
  1. Wait for an authorization request: GET /oauth/authorize arrives with its parameters in the query, or POST with them in a form
  2. Find the realm of the host: the request has its realm
  3. Count the request against the authorize limit: the address is under its limit
  4. Check the parameters against the authorize schema: the parameters match the schema
  5. Find the client: the client is found
  6. Check the redirect URI against the client's registration: redirect_uri is registered
  7. Check the redirect URI against the environment policy: the environment permits the redirect URI
  8. Check that the client may use the endpoint: the client may use the endpoint
  9. Read the DPoP key the code is to be bound to: dpop_jkt is absent, unread or well formed
  10. Check a request for a registration: the registration is allowed
  11. Start a registration interaction: the interaction is stored
  12. The person registers at the ceremony page: the new password creates the account, which finishes the interaction
  13. End the interaction before anything is issued: the interaction is over
  14. Check the request again, as the endpoint checks it: the request still passes
  15. Find the session the interaction holds: the session is live: the request is decided again for it
  16. Refuse an agent scope above the client's cap: no agent scope is above the cap; the scopes are the requested ones the client's allowlist holds
  17. Refuse a QAuth API audience the client does not list: every QAuth API audience among the resources is one the client lists
  18. Read the consent, and decide whether the sign-in is fresh enough and the consent covers the request: no consent covers the request: the person is asked
  19. Send the person to consent: the consent step cannot show the resources, decided when the interaction finished
Tell the client its dpop_jkt is malformed
redirect, error=invalid_request
INTERACTION_UI_ENABLED is off, the default: the sign-in and the consent are the server-rendered pages, DPoP is on and dpop_jkt is not one base64url SHA-256 thumbprint, an operator provisioned the client (provisioned_by_operator): the system client or the seed manifest, the request carries the cookie of a live browser session of an enabled user, nothing in the request is refused after the session, it carries no prompt, or prompt=login, prompt=consent or prompt=create, the request carries no prompt=create, nothing asks for a fresh sign-in, or the sign-in is fresh enough for what asks, a stored consent covers every requested scope at each requested resource, or the client's administrative consent does (ADR-017 Decision 9), and nothing asks for the screen, the client and its redirect URI still pass when the interaction finishes or is cancelled, the session the interaction holds is live and its account may use it, when the request is decided again
  1. Wait for an authorization request: GET /oauth/authorize arrives with its parameters in the query, or POST with them in a form
  2. Find the realm of the host: the request has its realm
  3. Count the request against the authorize limit: the address is under its limit
  4. Check the parameters against the authorize schema: the parameters match the schema
  5. Find the client: the client is found
  6. Check the redirect URI against the client's registration: redirect_uri is registered
  7. Check the redirect URI against the environment policy: the environment permits the redirect URI
  8. Check that the client may use the endpoint: the client may use the endpoint
  9. Read the DPoP key the code is to be bound to: dpop_jkt is not one thumbprint, for a client an operator provisioned
Show, rather than redirect, the dpop_jkt error of a client no operator provisioned
no redirect, page shown
INTERACTION_UI_ENABLED is off, the default: the sign-in and the consent are the server-rendered pages, DPoP is on and dpop_jkt is not one base64url SHA-256 thumbprint, the client registered itself: open registration, CIMD or a developer account, the request carries the cookie of a live browser session of an enabled user, nothing in the request is refused after the session, it carries no prompt, or prompt=login, prompt=consent or prompt=create, the request carries no prompt=create, nothing asks for a fresh sign-in, or the sign-in is fresh enough for what asks, a stored consent covers every requested scope at each requested resource, or the client's administrative consent does (ADR-017 Decision 9), and nothing asks for the screen, the client and its redirect URI still pass when the interaction finishes or is cancelled, the session the interaction holds is live and its account may use it, when the request is decided again
  1. Wait for an authorization request: GET /oauth/authorize arrives with its parameters in the query, or POST with them in a form
  2. Find the realm of the host: the request has its realm
  3. Count the request against the authorize limit: the address is under its limit
  4. Check the parameters against the authorize schema: the parameters match the schema
  5. Find the client: the client is found
  6. Check the redirect URI against the client's registration: redirect_uri is registered
  7. Check the redirect URI against the environment policy: the environment permits the redirect URI
  8. Check that the client may use the endpoint: the client may use the endpoint
  9. Read the DPoP key the code is to be bound to: dpop_jkt is not one thumbprint, for a client no operator provisioned
Tell the client prompt=create needs the openid scope
redirect, error=invalid_request
INTERACTION_UI_ENABLED is off, the default: the sign-in and the consent are the server-rendered pages, the host is the primary host of an enabled realm, the address is under its limit, the parameters pass the route schema, and the client, its redirect URI, its grant and response type and dpop_jkt all pass, an operator provisioned the client (provisioned_by_operator): the system client or the seed manifest, the request carries the cookie of a live browser session of an enabled user, nothing in the request is refused after the session, it carries no prompt, or prompt=login, prompt=consent or prompt=create, prompt=create without the openid scope, nothing asks for a fresh sign-in, or the sign-in is fresh enough for what asks, a stored consent covers every requested scope at each requested resource, or the client's administrative consent does (ADR-017 Decision 9), and nothing asks for the screen, the client and its redirect URI still pass when the interaction finishes or is cancelled, the session the interaction holds is live and its account may use it, when the request is decided again
  1. Wait for an authorization request: GET /oauth/authorize arrives with its parameters in the query, or POST with them in a form
  2. Find the realm of the host: the request has its realm
  3. Count the request against the authorize limit: the address is under its limit
  4. Check the parameters against the authorize schema: the parameters match the schema
  5. Find the client: the client is found
  6. Check the redirect URI against the client's registration: redirect_uri is registered
  7. Check the redirect URI against the environment policy: the environment permits the redirect URI
  8. Check that the client may use the endpoint: the client may use the endpoint
  9. Read the DPoP key the code is to be bound to: dpop_jkt is absent, unread or well formed
  10. Check a request for a registration: prompt=create without openid, for a client an operator provisioned
Show, rather than redirect, the openid error of a client no operator provisioned
no redirect, page shown
INTERACTION_UI_ENABLED is off, the default: the sign-in and the consent are the server-rendered pages, the host is the primary host of an enabled realm, the address is under its limit, the parameters pass the route schema, and the client, its redirect URI, its grant and response type and dpop_jkt all pass, the client registered itself: open registration, CIMD or a developer account, the request carries the cookie of a live browser session of an enabled user, nothing in the request is refused after the session, it carries no prompt, or prompt=login, prompt=consent or prompt=create, prompt=create without the openid scope, nothing asks for a fresh sign-in, or the sign-in is fresh enough for what asks, a stored consent covers every requested scope at each requested resource, or the client's administrative consent does (ADR-017 Decision 9), and nothing asks for the screen, the client and its redirect URI still pass when the interaction finishes or is cancelled, the session the interaction holds is live and its account may use it, when the request is decided again
  1. Wait for an authorization request: GET /oauth/authorize arrives with its parameters in the query, or POST with them in a form
  2. Find the realm of the host: the request has its realm
  3. Count the request against the authorize limit: the address is under its limit
  4. Check the parameters against the authorize schema: the parameters match the schema
  5. Find the client: the client is found
  6. Check the redirect URI against the client's registration: redirect_uri is registered
  7. Check the redirect URI against the environment policy: the environment permits the redirect URI
  8. Check that the client may use the endpoint: the client may use the endpoint
  9. Read the DPoP key the code is to be bound to: dpop_jkt is absent, unread or well formed
  10. Check a request for a registration: prompt=create without openid, for a client no operator provisioned
Tell the client the realm offers no sign-up
redirect, error=invalid_request
INTERACTION_UI_ENABLED is off, the default: the sign-in and the consent are the server-rendered pages, the host is the primary host of an enabled realm, the address is under its limit, the parameters pass the route schema, and the client, its redirect URI, its grant and response type and dpop_jkt all pass, an operator provisioned the client (provisioned_by_operator): the system client or the seed manifest, the request carries the cookie of a live browser session of an enabled user, nothing in the request is refused after the session, it carries no prompt, or prompt=login, prompt=consent or prompt=create, prompt=create with openid, and the realm's accounts.allowSignUp is off, nothing asks for a fresh sign-in, or the sign-in is fresh enough for what asks, a stored consent covers every requested scope at each requested resource, or the client's administrative consent does (ADR-017 Decision 9), and nothing asks for the screen, the client and its redirect URI still pass when the interaction finishes or is cancelled, the session the interaction holds is live and its account may use it, when the request is decided again
  1. Wait for an authorization request: GET /oauth/authorize arrives with its parameters in the query, or POST with them in a form
  2. Find the realm of the host: the request has its realm
  3. Count the request against the authorize limit: the address is under its limit
  4. Check the parameters against the authorize schema: the parameters match the schema
  5. Find the client: the client is found
  6. Check the redirect URI against the client's registration: redirect_uri is registered
  7. Check the redirect URI against the environment policy: the environment permits the redirect URI
  8. Check that the client may use the endpoint: the client may use the endpoint
  9. Read the DPoP key the code is to be bound to: dpop_jkt is absent, unread or well formed
  10. Check a request for a registration: the realm offers no sign-up, for a client an operator provisioned
Show, rather than redirect, the sign-up refusal of a client no operator provisioned
no redirect, page shown
INTERACTION_UI_ENABLED is off, the default: the sign-in and the consent are the server-rendered pages, the host is the primary host of an enabled realm, the address is under its limit, the parameters pass the route schema, and the client, its redirect URI, its grant and response type and dpop_jkt all pass, the client registered itself: open registration, CIMD or a developer account, the request carries the cookie of a live browser session of an enabled user, nothing in the request is refused after the session, it carries no prompt, or prompt=login, prompt=consent or prompt=create, prompt=create with openid, and the realm's accounts.allowSignUp is off, nothing asks for a fresh sign-in, or the sign-in is fresh enough for what asks, a stored consent covers every requested scope at each requested resource, or the client's administrative consent does (ADR-017 Decision 9), and nothing asks for the screen, the client and its redirect URI still pass when the interaction finishes or is cancelled, the session the interaction holds is live and its account may use it, when the request is decided again
  1. Wait for an authorization request: GET /oauth/authorize arrives with its parameters in the query, or POST with them in a form
  2. Find the realm of the host: the request has its realm
  3. Count the request against the authorize limit: the address is under its limit
  4. Check the parameters against the authorize schema: the parameters match the schema
  5. Find the client: the client is found
  6. Check the redirect URI against the client's registration: redirect_uri is registered
  7. Check the redirect URI against the environment policy: the environment permits the redirect URI
  8. Check that the client may use the endpoint: the client may use the endpoint
  9. Read the DPoP key the code is to be bound to: dpop_jkt is absent, unread or well formed
  10. Check a request for a registration: the realm offers no sign-up, for a client no operator provisioned
Tell the client it may not register accounts
redirect, error=unauthorized_client
INTERACTION_UI_ENABLED is on: the sign-in and the consent are interactions (#628), the host is the primary host of an enabled realm, the address is under its limit, the parameters pass the route schema, and the client, its redirect URI, its grant and response type and dpop_jkt all pass, an operator provisioned the client (provisioned_by_operator): the system client or the seed manifest, the request carries the cookie of a live browser session of an enabled user, nothing in the request is refused after the session, it carries no prompt, or prompt=login, prompt=consent or prompt=create, prompt=create with openid, the realm allows sign-up, and the client's operator-set hosted_flows do not name register, nothing asks for a fresh sign-in, or the sign-in is fresh enough for what asks, a stored consent covers every requested scope at each requested resource, or the client's administrative consent does (ADR-017 Decision 9), and nothing asks for the screen, the client and its redirect URI still pass when the interaction finishes or is cancelled, the session the interaction holds is live and its account may use it, when the request is decided again
  1. Wait for an authorization request: GET /oauth/authorize arrives with its parameters in the query, or POST with them in a form
  2. Find the realm of the host: the request has its realm
  3. Count the request against the authorize limit: the address is under its limit
  4. Check the parameters against the authorize schema: the parameters match the schema
  5. Find the client: the client is found
  6. Check the redirect URI against the client's registration: redirect_uri is registered
  7. Check the redirect URI against the environment policy: the environment permits the redirect URI
  8. Check that the client may use the endpoint: the client may use the endpoint
  9. Read the DPoP key the code is to be bound to: dpop_jkt is absent, unread or well formed
  10. Check a request for a registration: the client may not register accounts, for a client an operator provisioned
Show, rather than redirect, the registration refusal of a client no operator provisioned
no redirect, page shown
INTERACTION_UI_ENABLED is on: the sign-in and the consent are interactions (#628), the host is the primary host of an enabled realm, the address is under its limit, the parameters pass the route schema, and the client, its redirect URI, its grant and response type and dpop_jkt all pass, the client registered itself: open registration, CIMD or a developer account, the request carries the cookie of a live browser session of an enabled user, nothing in the request is refused after the session, it carries no prompt, or prompt=login, prompt=consent or prompt=create, prompt=create with openid, the realm allows sign-up, and the client's operator-set hosted_flows do not name register, nothing asks for a fresh sign-in, or the sign-in is fresh enough for what asks, a stored consent covers every requested scope at each requested resource, or the client's administrative consent does (ADR-017 Decision 9), and nothing asks for the screen, the client and its redirect URI still pass when the interaction finishes or is cancelled, the session the interaction holds is live and its account may use it, when the request is decided again
  1. Wait for an authorization request: GET /oauth/authorize arrives with its parameters in the query, or POST with them in a form
  2. Find the realm of the host: the request has its realm
  3. Count the request against the authorize limit: the address is under its limit
  4. Check the parameters against the authorize schema: the parameters match the schema
  5. Find the client: the client is found
  6. Check the redirect URI against the client's registration: redirect_uri is registered
  7. Check the redirect URI against the environment policy: the environment permits the redirect URI
  8. Check that the client may use the endpoint: the client may use the endpoint
  9. Read the DPoP key the code is to be bound to: dpop_jkt is absent, unread or well formed
  10. Check a request for a registration: the client may not register accounts, for a client no operator provisioned
Tell the client prompt=create takes no max_age
redirect, error=invalid_request
INTERACTION_UI_ENABLED is on: the sign-in and the consent are interactions (#628), the host is the primary host of an enabled realm, the address is under its limit, the parameters pass the route schema, and the client, its redirect URI, its grant and response type and dpop_jkt all pass, an operator provisioned the client (provisioned_by_operator): the system client or the seed manifest, the request carries the cookie of a live browser session of an enabled user, nothing in the request is refused after the session, it carries no prompt, or prompt=login, prompt=consent or prompt=create, prompt=create with openid and max_age, the realm and the client allowing sign-up, nothing asks for a fresh sign-in, or the sign-in is fresh enough for what asks, a stored consent covers every requested scope at each requested resource, or the client's administrative consent does (ADR-017 Decision 9), and nothing asks for the screen, the client and its redirect URI still pass when the interaction finishes or is cancelled, the session the interaction holds is live and its account may use it, when the request is decided again
  1. Wait for an authorization request: GET /oauth/authorize arrives with its parameters in the query, or POST with them in a form
  2. Find the realm of the host: the request has its realm
  3. Count the request against the authorize limit: the address is under its limit
  4. Check the parameters against the authorize schema: the parameters match the schema
  5. Find the client: the client is found
  6. Check the redirect URI against the client's registration: redirect_uri is registered
  7. Check the redirect URI against the environment policy: the environment permits the redirect URI
  8. Check that the client may use the endpoint: the client may use the endpoint
  9. Read the DPoP key the code is to be bound to: dpop_jkt is absent, unread or well formed
  10. Check a request for a registration: prompt=create with max_age, for a client an operator provisioned
Show, rather than redirect, the max_age error of a client no operator provisioned
no redirect, page shown
INTERACTION_UI_ENABLED is on: the sign-in and the consent are interactions (#628), the host is the primary host of an enabled realm, the address is under its limit, the parameters pass the route schema, and the client, its redirect URI, its grant and response type and dpop_jkt all pass, the client registered itself: open registration, CIMD or a developer account, the request carries the cookie of a live browser session of an enabled user, nothing in the request is refused after the session, it carries no prompt, or prompt=login, prompt=consent or prompt=create, prompt=create with openid and max_age, the realm and the client allowing sign-up, nothing asks for a fresh sign-in, or the sign-in is fresh enough for what asks, a stored consent covers every requested scope at each requested resource, or the client's administrative consent does (ADR-017 Decision 9), and nothing asks for the screen, the client and its redirect URI still pass when the interaction finishes or is cancelled, the session the interaction holds is live and its account may use it, when the request is decided again
  1. Wait for an authorization request: GET /oauth/authorize arrives with its parameters in the query, or POST with them in a form
  2. Find the realm of the host: the request has its realm
  3. Count the request against the authorize limit: the address is under its limit
  4. Check the parameters against the authorize schema: the parameters match the schema
  5. Find the client: the client is found
  6. Check the redirect URI against the client's registration: redirect_uri is registered
  7. Check the redirect URI against the environment policy: the environment permits the redirect URI
  8. Check that the client may use the endpoint: the client may use the endpoint
  9. Read the DPoP key the code is to be bound to: dpop_jkt is absent, unread or well formed
  10. Check a request for a registration: prompt=create with max_age, for a client no operator provisioned
Tell the client prompt=none found no session
redirect, error=login_required
INTERACTION_UI_ENABLED is off, the default: the sign-in and the consent are the server-rendered pages, the host is the primary host of an enabled realm, the address is under its limit, the parameters pass the route schema, and the client, its redirect URI, its grant and response type and dpop_jkt all pass, an operator provisioned the client (provisioned_by_operator): the system client or the seed manifest, the request carries no session cookie, or one that names a cookie key this process has not read yet and may not read again yet (#493), which is left for the next request, nothing in the request is refused after the session, the request carries prompt=none: no page may be shown, the request carries no prompt=create, nothing asks for a fresh sign-in, or the sign-in is fresh enough for what asks, a stored consent covers every requested scope at each requested resource, or the client's administrative consent does (ADR-017 Decision 9), and nothing asks for the screen, the client and its redirect URI still pass when the interaction finishes or is cancelled, the session the interaction holds is live and its account may use it, when the request is decided again
  1. Wait for an authorization request: GET /oauth/authorize arrives with its parameters in the query, or POST with them in a form
  2. Find the realm of the host: the request has its realm
  3. Count the request against the authorize limit: the address is under its limit
  4. Check the parameters against the authorize schema: the parameters match the schema
  5. Find the client: the client is found
  6. Check the redirect URI against the client's registration: redirect_uri is registered
  7. Check the redirect URI against the environment policy: the environment permits the redirect URI
  8. Check that the client may use the endpoint: the client may use the endpoint
  9. Read the DPoP key the code is to be bound to: dpop_jkt is absent, unread or well formed
  10. Check a request for a registration: the request carries no prompt=create
  11. Find the browser session: no usable session under prompt=none, for a client an operator provisioned; step_up.required is recorded
Show, rather than redirect, the login_required of a client no operator provisioned
no redirect, page shown
INTERACTION_UI_ENABLED is off, the default: the sign-in and the consent are the server-rendered pages, the host is the primary host of an enabled realm, the address is under its limit, the parameters pass the route schema, and the client, its redirect URI, its grant and response type and dpop_jkt all pass, the client registered itself: open registration, CIMD or a developer account, the request carries no session cookie, or one that names a cookie key this process has not read yet and may not read again yet (#493), which is left for the next request, nothing in the request is refused after the session, the request carries prompt=none: no page may be shown, the request carries no prompt=create, nothing asks for a fresh sign-in, or the sign-in is fresh enough for what asks, a stored consent covers every requested scope at each requested resource, or the client's administrative consent does (ADR-017 Decision 9), and nothing asks for the screen, the client and its redirect URI still pass when the interaction finishes or is cancelled, the session the interaction holds is live and its account may use it, when the request is decided again
  1. Wait for an authorization request: GET /oauth/authorize arrives with its parameters in the query, or POST with them in a form
  2. Find the realm of the host: the request has its realm
  3. Count the request against the authorize limit: the address is under its limit
  4. Check the parameters against the authorize schema: the parameters match the schema
  5. Find the client: the client is found
  6. Check the redirect URI against the client's registration: redirect_uri is registered
  7. Check the redirect URI against the environment policy: the environment permits the redirect URI
  8. Check that the client may use the endpoint: the client may use the endpoint
  9. Read the DPoP key the code is to be bound to: dpop_jkt is absent, unread or well formed
  10. Check a request for a registration: the request carries no prompt=create
  11. Find the browser session: no usable session under prompt=none, for a client no operator provisioned
Tell the client an agent scope is above its cap
redirect, error=invalid_scope
INTERACTION_UI_ENABLED is off, the default: the sign-in and the consent are the server-rendered pages, the host is the primary host of an enabled realm, the address is under its limit, the parameters pass the route schema, and the client, its redirect URI, its grant and response type and dpop_jkt all pass, an operator provisioned the client (provisioned_by_operator): the system client or the seed manifest, the request carries the cookie of a live browser session of an enabled user, the scope parameter names an agent:* scope above the client's agent mode cap (any agent:* scope for a client that is no agent or has no cap), it carries no prompt, or prompt=login, prompt=consent or prompt=create, the request carries no prompt=create, nothing asks for a fresh sign-in, or the sign-in is fresh enough for what asks, a stored consent covers every requested scope at each requested resource, or the client's administrative consent does (ADR-017 Decision 9), and nothing asks for the screen, the client and its redirect URI still pass when the interaction finishes or is cancelled, the session the interaction holds is live and its account may use it, when the request is decided again
  1. Wait for an authorization request: GET /oauth/authorize arrives with its parameters in the query, or POST with them in a form
  2. Find the realm of the host: the request has its realm
  3. Count the request against the authorize limit: the address is under its limit
  4. Check the parameters against the authorize schema: the parameters match the schema
  5. Find the client: the client is found
  6. Check the redirect URI against the client's registration: redirect_uri is registered
  7. Check the redirect URI against the environment policy: the environment permits the redirect URI
  8. Check that the client may use the endpoint: the client may use the endpoint
  9. Read the DPoP key the code is to be bound to: dpop_jkt is absent, unread or well formed
  10. Check a request for a registration: the request carries no prompt=create
  11. Find the browser session: the session is live
  12. Refuse an agent scope above the client's cap: an agent scope is above the cap, for a client an operator provisioned
Show, rather than redirect, the agent-cap error of a client no operator provisioned
no redirect, page shown
INTERACTION_UI_ENABLED is off, the default: the sign-in and the consent are the server-rendered pages, the host is the primary host of an enabled realm, the address is under its limit, the parameters pass the route schema, and the client, its redirect URI, its grant and response type and dpop_jkt all pass, the client registered itself: open registration, CIMD or a developer account, the request carries the cookie of a live browser session of an enabled user, the scope parameter names an agent:* scope above the client's agent mode cap (any agent:* scope for a client that is no agent or has no cap), it carries no prompt, or prompt=login, prompt=consent or prompt=create, the request carries no prompt=create, nothing asks for a fresh sign-in, or the sign-in is fresh enough for what asks, a stored consent covers every requested scope at each requested resource, or the client's administrative consent does (ADR-017 Decision 9), and nothing asks for the screen, the client and its redirect URI still pass when the interaction finishes or is cancelled, the session the interaction holds is live and its account may use it, when the request is decided again
  1. Wait for an authorization request: GET /oauth/authorize arrives with its parameters in the query, or POST with them in a form
  2. Find the realm of the host: the request has its realm
  3. Count the request against the authorize limit: the address is under its limit
  4. Check the parameters against the authorize schema: the parameters match the schema
  5. Find the client: the client is found
  6. Check the redirect URI against the client's registration: redirect_uri is registered
  7. Check the redirect URI against the environment policy: the environment permits the redirect URI
  8. Check that the client may use the endpoint: the client may use the endpoint
  9. Read the DPoP key the code is to be bound to: dpop_jkt is absent, unread or well formed
  10. Check a request for a registration: the request carries no prompt=create
  11. Find the browser session: the session is live
  12. Refuse an agent scope above the client's cap: an agent scope is above the cap, for a client no operator provisioned
Tell the client it named a QAuth API audience it does not list
redirect, error=invalid_target
INTERACTION_UI_ENABLED is off, the default: the sign-in and the consent are the server-rendered pages, the host is the primary host of an enabled realm, the address is under its limit, the parameters pass the route schema, and the client, its redirect URI, its grant and response type and dpop_jkt all pass, an operator provisioned the client (provisioned_by_operator): the system client or the seed manifest, the request carries the cookie of a live browser session of an enabled user, a resource indicator names a QAuth API audience (urn:qauth:aud:) the client does not list, it carries no prompt, or prompt=login, prompt=consent or prompt=create, the request carries no prompt=create, nothing asks for a fresh sign-in, or the sign-in is fresh enough for what asks, a stored consent covers every requested scope at each requested resource, or the client's administrative consent does (ADR-017 Decision 9), and nothing asks for the screen, the client and its redirect URI still pass when the interaction finishes or is cancelled, the session the interaction holds is live and its account may use it, when the request is decided again
  1. Wait for an authorization request: GET /oauth/authorize arrives with its parameters in the query, or POST with them in a form
  2. Find the realm of the host: the request has its realm
  3. Count the request against the authorize limit: the address is under its limit
  4. Check the parameters against the authorize schema: the parameters match the schema
  5. Find the client: the client is found
  6. Check the redirect URI against the client's registration: redirect_uri is registered
  7. Check the redirect URI against the environment policy: the environment permits the redirect URI
  8. Check that the client may use the endpoint: the client may use the endpoint
  9. Read the DPoP key the code is to be bound to: dpop_jkt is absent, unread or well formed
  10. Check a request for a registration: the request carries no prompt=create
  11. Find the browser session: the session is live
  12. Refuse an agent scope above the client's cap: no agent scope is above the cap; the scopes are the requested ones the client's allowlist holds
  13. Refuse a QAuth API audience the client does not list: a resource names a QAuth API audience the client does not list, for a client an operator provisioned
Show, rather than redirect, the audience error of a client no operator provisioned
no redirect, page shown
INTERACTION_UI_ENABLED is off, the default: the sign-in and the consent are the server-rendered pages, the host is the primary host of an enabled realm, the address is under its limit, the parameters pass the route schema, and the client, its redirect URI, its grant and response type and dpop_jkt all pass, the client registered itself: open registration, CIMD or a developer account, the request carries the cookie of a live browser session of an enabled user, a resource indicator names a QAuth API audience (urn:qauth:aud:) the client does not list, it carries no prompt, or prompt=login, prompt=consent or prompt=create, the request carries no prompt=create, nothing asks for a fresh sign-in, or the sign-in is fresh enough for what asks, a stored consent covers every requested scope at each requested resource, or the client's administrative consent does (ADR-017 Decision 9), and nothing asks for the screen, the client and its redirect URI still pass when the interaction finishes or is cancelled, the session the interaction holds is live and its account may use it, when the request is decided again
  1. Wait for an authorization request: GET /oauth/authorize arrives with its parameters in the query, or POST with them in a form
  2. Find the realm of the host: the request has its realm
  3. Count the request against the authorize limit: the address is under its limit
  4. Check the parameters against the authorize schema: the parameters match the schema
  5. Find the client: the client is found
  6. Check the redirect URI against the client's registration: redirect_uri is registered
  7. Check the redirect URI against the environment policy: the environment permits the redirect URI
  8. Check that the client may use the endpoint: the client may use the endpoint
  9. Read the DPoP key the code is to be bound to: dpop_jkt is absent, unread or well formed
  10. Check a request for a registration: the request carries no prompt=create
  11. Find the browser session: the session is live
  12. Refuse an agent scope above the client's cap: no agent scope is above the cap; the scopes are the requested ones the client's allowlist holds
  13. Refuse a QAuth API audience the client does not list: a resource names a QAuth API audience the client does not list, for a client no operator provisioned
Tell the client prompt=none cannot give the fresh sign-in the request needs
redirect, error=login_required
INTERACTION_UI_ENABLED is off, the default: the sign-in and the consent are the server-rendered pages, the host is the primary host of an enabled realm, the address is under its limit, the parameters pass the route schema, and the client, its redirect URI, its grant and response type and dpop_jkt all pass, an operator provisioned the client (provisioned_by_operator): the system client or the seed manifest, the request carries the cookie of a live browser session of an enabled user, nothing in the request is refused after the session, the request carries prompt=none: no page may be shown, the request carries no prompt=create, prompt=login, a dangerous scope (write:*, agent:admin, agent:exec) outside development, or a native_backend client asks for a sign-in within the last two minutes and it is older; or max_age asks for one within that many whole seconds and it is older, a stored consent covers every requested scope at each requested resource, or the client's administrative consent does (ADR-017 Decision 9), and nothing asks for the screen, the client and its redirect URI still pass when the interaction finishes or is cancelled, the session the interaction holds is live and its account may use it, when the request is decided again
  1. Wait for an authorization request: GET /oauth/authorize arrives with its parameters in the query, or POST with them in a form
  2. Find the realm of the host: the request has its realm
  3. Count the request against the authorize limit: the address is under its limit
  4. Check the parameters against the authorize schema: the parameters match the schema
  5. Find the client: the client is found
  6. Check the redirect URI against the client's registration: redirect_uri is registered
  7. Check the redirect URI against the environment policy: the environment permits the redirect URI
  8. Check that the client may use the endpoint: the client may use the endpoint
  9. Read the DPoP key the code is to be bound to: dpop_jkt is absent, unread or well formed
  10. Check a request for a registration: the request carries no prompt=create
  11. Find the browser session: the session is live
  12. Refuse an agent scope above the client's cap: no agent scope is above the cap; the scopes are the requested ones the client's allowlist holds
  13. Refuse a QAuth API audience the client does not list: every QAuth API audience among the resources is one the client lists
  14. Read the consent, and decide whether the sign-in is fresh enough and the consent covers the request: prompt=none, and the sign-in is too old for what is asked, for a client an operator provisioned
Show, rather than redirect, that error for a client no operator provisioned
no redirect, page shown
INTERACTION_UI_ENABLED is off, the default: the sign-in and the consent are the server-rendered pages, the host is the primary host of an enabled realm, the address is under its limit, the parameters pass the route schema, and the client, its redirect URI, its grant and response type and dpop_jkt all pass, the client registered itself: open registration, CIMD or a developer account, the request carries the cookie of a live browser session of an enabled user, nothing in the request is refused after the session, the request carries prompt=none: no page may be shown, the request carries no prompt=create, prompt=login, a dangerous scope (write:*, agent:admin, agent:exec) outside development, or a native_backend client asks for a sign-in within the last two minutes and it is older; or max_age asks for one within that many whole seconds and it is older, a stored consent covers every requested scope at each requested resource, or the client's administrative consent does (ADR-017 Decision 9), and nothing asks for the screen, the client and its redirect URI still pass when the interaction finishes or is cancelled, the session the interaction holds is live and its account may use it, when the request is decided again
  1. Wait for an authorization request: GET /oauth/authorize arrives with its parameters in the query, or POST with them in a form
  2. Find the realm of the host: the request has its realm
  3. Count the request against the authorize limit: the address is under its limit
  4. Check the parameters against the authorize schema: the parameters match the schema
  5. Find the client: the client is found
  6. Check the redirect URI against the client's registration: redirect_uri is registered
  7. Check the redirect URI against the environment policy: the environment permits the redirect URI
  8. Check that the client may use the endpoint: the client may use the endpoint
  9. Read the DPoP key the code is to be bound to: dpop_jkt is absent, unread or well formed
  10. Check a request for a registration: the request carries no prompt=create
  11. Find the browser session: the session is live
  12. Refuse an agent scope above the client's cap: no agent scope is above the cap; the scopes are the requested ones the client's allowlist holds
  13. Refuse a QAuth API audience the client does not list: every QAuth API audience among the resources is one the client lists
  14. Read the consent, and decide whether the sign-in is fresh enough and the consent covers the request: prompt=none, and the sign-in is too old for what is asked, for a client no operator provisioned
Tell the client prompt=none cannot ask for the consent the request needs
redirect, error=consent_required
INTERACTION_UI_ENABLED is off, the default: the sign-in and the consent are the server-rendered pages, the host is the primary host of an enabled realm, the address is under its limit, the parameters pass the route schema, and the client, its redirect URI, its grant and response type and dpop_jkt all pass, an operator provisioned the client (provisioned_by_operator): the system client or the seed manifest, the request carries the cookie of a live browser session of an enabled user, nothing in the request is refused after the session, the request carries prompt=none: no page may be shown, the request carries no prompt=create, nothing asks for a fresh sign-in, or the sign-in is fresh enough for what asks, no stored consent covers the request, prompt=consent asks for the screen, the request widens a prior grant, or the client is an AI agent, which never skips the screen (ADR-015 Decision 11), the client and its redirect URI still pass when the interaction finishes or is cancelled, the session the interaction holds is live and its account may use it, when the request is decided again
  1. Wait for an authorization request: GET /oauth/authorize arrives with its parameters in the query, or POST with them in a form
  2. Find the realm of the host: the request has its realm
  3. Count the request against the authorize limit: the address is under its limit
  4. Check the parameters against the authorize schema: the parameters match the schema
  5. Find the client: the client is found
  6. Check the redirect URI against the client's registration: redirect_uri is registered
  7. Check the redirect URI against the environment policy: the environment permits the redirect URI
  8. Check that the client may use the endpoint: the client may use the endpoint
  9. Read the DPoP key the code is to be bound to: dpop_jkt is absent, unread or well formed
  10. Check a request for a registration: the request carries no prompt=create
  11. Find the browser session: the session is live
  12. Refuse an agent scope above the client's cap: no agent scope is above the cap; the scopes are the requested ones the client's allowlist holds
  13. Refuse a QAuth API audience the client does not list: every QAuth API audience among the resources is one the client lists
  14. Read the consent, and decide whether the sign-in is fresh enough and the consent covers the request: prompt=none, and no consent covers the request, for a client an operator provisioned
Show, rather than redirect, that error for a client no operator provisioned
no redirect, page shown
INTERACTION_UI_ENABLED is off, the default: the sign-in and the consent are the server-rendered pages, the host is the primary host of an enabled realm, the address is under its limit, the parameters pass the route schema, and the client, its redirect URI, its grant and response type and dpop_jkt all pass, the client registered itself: open registration, CIMD or a developer account, the request carries the cookie of a live browser session of an enabled user, nothing in the request is refused after the session, the request carries prompt=none: no page may be shown, the request carries no prompt=create, nothing asks for a fresh sign-in, or the sign-in is fresh enough for what asks, no stored consent covers the request, prompt=consent asks for the screen, the request widens a prior grant, or the client is an AI agent, which never skips the screen (ADR-015 Decision 11), the client and its redirect URI still pass when the interaction finishes or is cancelled, the session the interaction holds is live and its account may use it, when the request is decided again
  1. Wait for an authorization request: GET /oauth/authorize arrives with its parameters in the query, or POST with them in a form
  2. Find the realm of the host: the request has its realm
  3. Count the request against the authorize limit: the address is under its limit
  4. Check the parameters against the authorize schema: the parameters match the schema
  5. Find the client: the client is found
  6. Check the redirect URI against the client's registration: redirect_uri is registered
  7. Check the redirect URI against the environment policy: the environment permits the redirect URI
  8. Check that the client may use the endpoint: the client may use the endpoint
  9. Read the DPoP key the code is to be bound to: dpop_jkt is absent, unread or well formed
  10. Check a request for a registration: the request carries no prompt=create
  11. Find the browser session: the session is live
  12. Refuse an agent scope above the client's cap: no agent scope is above the cap; the scopes are the requested ones the client's allowlist holds
  13. Refuse a QAuth API audience the client does not list: every QAuth API audience among the resources is one the client lists
  14. Read the consent, and decide whether the sign-in is fresh enough and the consent covers the request: prompt=none, and no consent covers the request, for a client no operator provisioned
Tell the client under prompt=none that the session ended under the request
redirect, error=login_required
INTERACTION_UI_ENABLED is off, the default: the sign-in and the consent are the server-rendered pages, the host is the primary host of an enabled realm, the address is under its limit, the parameters pass the route schema, and the client, its redirect URI, its grant and response type and dpop_jkt all pass, an operator provisioned the client (provisioned_by_operator): the system client or the seed manifest, the request carries the cookie of a live browser session of an enabled user, nothing in the request is refused after the session, the request carries prompt=none: no page may be shown, the request carries no prompt=create, nothing asks for a fresh sign-in, or the sign-in is fresh enough for what asks, a stored consent covers every requested scope at each requested resource, or the client's administrative consent does (ADR-017 Decision 9), and nothing asks for the screen, the client and its redirect URI still pass when the interaction finishes or is cancelled, the session the interaction holds is live and its account may use it, when the request is decided again
  1. Wait for an authorization request: GET /oauth/authorize arrives with its parameters in the query, or POST with them in a form
  2. Find the realm of the host: the request has its realm
  3. Count the request against the authorize limit: the address is under its limit
  4. Check the parameters against the authorize schema: the parameters match the schema
  5. Find the client: the client is found
  6. Check the redirect URI against the client's registration: redirect_uri is registered
  7. Check the redirect URI against the environment policy: the environment permits the redirect URI
  8. Check that the client may use the endpoint: the client may use the endpoint
  9. Read the DPoP key the code is to be bound to: dpop_jkt is absent, unread or well formed
  10. Check a request for a registration: the request carries no prompt=create
  11. Find the browser session: the session is live
  12. Refuse an agent scope above the client's cap: no agent scope is above the cap; the scopes are the requested ones the client's allowlist holds
  13. Refuse a QAuth API audience the client does not list: every QAuth API audience among the resources is one the client lists
  14. Read the consent, and decide whether the sign-in is fresh enough and the consent covers the request: the sign-in is fresh enough and a consent covers the request
  15. Mint the authorization code under the consent and the session: it fails, because the session ended under the request, under prompt=none, for a client an operator provisioned
Show, rather than redirect, that error for a client no operator provisioned
no redirect, page shown
INTERACTION_UI_ENABLED is off, the default: the sign-in and the consent are the server-rendered pages, the host is the primary host of an enabled realm, the address is under its limit, the parameters pass the route schema, and the client, its redirect URI, its grant and response type and dpop_jkt all pass, the client registered itself: open registration, CIMD or a developer account, the request carries the cookie of a live browser session of an enabled user, nothing in the request is refused after the session, the request carries prompt=none: no page may be shown, the request carries no prompt=create, nothing asks for a fresh sign-in, or the sign-in is fresh enough for what asks, a stored consent covers every requested scope at each requested resource, or the client's administrative consent does (ADR-017 Decision 9), and nothing asks for the screen, the client and its redirect URI still pass when the interaction finishes or is cancelled, the session the interaction holds is live and its account may use it, when the request is decided again
  1. Wait for an authorization request: GET /oauth/authorize arrives with its parameters in the query, or POST with them in a form
  2. Find the realm of the host: the request has its realm
  3. Count the request against the authorize limit: the address is under its limit
  4. Check the parameters against the authorize schema: the parameters match the schema
  5. Find the client: the client is found
  6. Check the redirect URI against the client's registration: redirect_uri is registered
  7. Check the redirect URI against the environment policy: the environment permits the redirect URI
  8. Check that the client may use the endpoint: the client may use the endpoint
  9. Read the DPoP key the code is to be bound to: dpop_jkt is absent, unread or well formed
  10. Check a request for a registration: the request carries no prompt=create
  11. Find the browser session: the session is live
  12. Refuse an agent scope above the client's cap: no agent scope is above the cap; the scopes are the requested ones the client's allowlist holds
  13. Refuse a QAuth API audience the client does not list: every QAuth API audience among the resources is one the client lists
  14. Read the consent, and decide whether the sign-in is fresh enough and the consent covers the request: the sign-in is fresh enough and a consent covers the request
  15. Mint the authorization code under the consent and the session: it fails, because the session ended under the request, under prompt=none, for a client no operator provisioned
Tell the client under prompt=none that the consent was revoked under the request
redirect, error=consent_required
INTERACTION_UI_ENABLED is off, the default: the sign-in and the consent are the server-rendered pages, the host is the primary host of an enabled realm, the address is under its limit, the parameters pass the route schema, and the client, its redirect URI, its grant and response type and dpop_jkt all pass, an operator provisioned the client (provisioned_by_operator): the system client or the seed manifest, the request carries the cookie of a live browser session of an enabled user, nothing in the request is refused after the session, the request carries prompt=none: no page may be shown, the request carries no prompt=create, nothing asks for a fresh sign-in, or the sign-in is fresh enough for what asks, a stored consent covers every requested scope at each requested resource, or the client's administrative consent does (ADR-017 Decision 9), and nothing asks for the screen, the client and its redirect URI still pass when the interaction finishes or is cancelled, the session the interaction holds is live and its account may use it, when the request is decided again
  1. Wait for an authorization request: GET /oauth/authorize arrives with its parameters in the query, or POST with them in a form
  2. Find the realm of the host: the request has its realm
  3. Count the request against the authorize limit: the address is under its limit
  4. Check the parameters against the authorize schema: the parameters match the schema
  5. Find the client: the client is found
  6. Check the redirect URI against the client's registration: redirect_uri is registered
  7. Check the redirect URI against the environment policy: the environment permits the redirect URI
  8. Check that the client may use the endpoint: the client may use the endpoint
  9. Read the DPoP key the code is to be bound to: dpop_jkt is absent, unread or well formed
  10. Check a request for a registration: the request carries no prompt=create
  11. Find the browser session: the session is live
  12. Refuse an agent scope above the client's cap: no agent scope is above the cap; the scopes are the requested ones the client's allowlist holds
  13. Refuse a QAuth API audience the client does not list: every QAuth API audience among the resources is one the client lists
  14. Read the consent, and decide whether the sign-in is fresh enough and the consent covers the request: the sign-in is fresh enough and a consent covers the request
  15. Mint the authorization code under the consent and the session: it fails, because the consent was revoked under the request, under prompt=none, for a client an operator provisioned
Show, rather than redirect, that error for a client no operator provisioned
no redirect, page shown
INTERACTION_UI_ENABLED is off, the default: the sign-in and the consent are the server-rendered pages, the host is the primary host of an enabled realm, the address is under its limit, the parameters pass the route schema, and the client, its redirect URI, its grant and response type and dpop_jkt all pass, the client registered itself: open registration, CIMD or a developer account, the request carries the cookie of a live browser session of an enabled user, nothing in the request is refused after the session, the request carries prompt=none: no page may be shown, the request carries no prompt=create, nothing asks for a fresh sign-in, or the sign-in is fresh enough for what asks, a stored consent covers every requested scope at each requested resource, or the client's administrative consent does (ADR-017 Decision 9), and nothing asks for the screen, the client and its redirect URI still pass when the interaction finishes or is cancelled, the session the interaction holds is live and its account may use it, when the request is decided again
  1. Wait for an authorization request: GET /oauth/authorize arrives with its parameters in the query, or POST with them in a form
  2. Find the realm of the host: the request has its realm
  3. Count the request against the authorize limit: the address is under its limit
  4. Check the parameters against the authorize schema: the parameters match the schema
  5. Find the client: the client is found
  6. Check the redirect URI against the client's registration: redirect_uri is registered
  7. Check the redirect URI against the environment policy: the environment permits the redirect URI
  8. Check that the client may use the endpoint: the client may use the endpoint
  9. Read the DPoP key the code is to be bound to: dpop_jkt is absent, unread or well formed
  10. Check a request for a registration: the request carries no prompt=create
  11. Find the browser session: the session is live
  12. Refuse an agent scope above the client's cap: no agent scope is above the cap; the scopes are the requested ones the client's allowlist holds
  13. Refuse a QAuth API audience the client does not list: every QAuth API audience among the resources is one the client lists
  14. Read the consent, and decide whether the sign-in is fresh enough and the consent covers the request: the sign-in is fresh enough and a consent covers the request
  15. Mint the authorization code under the consent and the session: it fails, because the consent was revoked under the request, under prompt=none, for a client no operator provisioned
Tell the client the consent step cannot show its scopes
redirect, error=invalid_scope
INTERACTION_UI_ENABLED is on: the sign-in and the consent are interactions (#628), the host is the primary host of an enabled realm, the address is under its limit, the parameters pass the route schema, and the client, its redirect URI, its grant and response type and dpop_jkt all pass, an operator provisioned the client (provisioned_by_operator): the system client or the seed manifest, the request carries the cookie of a live browser session of an enabled user, the consent step cannot show the scopes: more than 64, or one outside its alphabet (RFC 6749 §3.3 without < and >) or over 128 characters; read only when an interaction asks for consent, it carries no prompt, or prompt=login, prompt=consent or prompt=create, the request carries no prompt=create, nothing asks for a fresh sign-in, or the sign-in is fresh enough for what asks, no stored consent covers the request, prompt=consent asks for the screen, the request widens a prior grant, or the client is an AI agent, which never skips the screen (ADR-015 Decision 11), the client and its redirect URI still pass when the interaction finishes or is cancelled, the session the interaction holds is live and its account may use it, when the request is decided again
  1. Wait for an authorization request: GET /oauth/authorize arrives with its parameters in the query, or POST with them in a form
  2. Find the realm of the host: the request has its realm
  3. Count the request against the authorize limit: the address is under its limit
  4. Check the parameters against the authorize schema: the parameters match the schema
  5. Find the client: the client is found
  6. Check the redirect URI against the client's registration: redirect_uri is registered
  7. Check the redirect URI against the environment policy: the environment permits the redirect URI
  8. Check that the client may use the endpoint: the client may use the endpoint
  9. Read the DPoP key the code is to be bound to: dpop_jkt is absent, unread or well formed
  10. Check a request for a registration: the request carries no prompt=create
  11. Find the browser session: the session is live
  12. Refuse an agent scope above the client's cap: no agent scope is above the cap; the scopes are the requested ones the client's allowlist holds
  13. Refuse a QAuth API audience the client does not list: every QAuth API audience among the resources is one the client lists
  14. Read the consent, and decide whether the sign-in is fresh enough and the consent covers the request: no consent covers the request: the person is asked
  15. Send the person to consent: the consent step cannot show the scopes, for a client an operator provisioned
Show, rather than redirect, that error for a client no operator provisioned
no redirect, page shown
INTERACTION_UI_ENABLED is on: the sign-in and the consent are interactions (#628), the host is the primary host of an enabled realm, the address is under its limit, the parameters pass the route schema, and the client, its redirect URI, its grant and response type and dpop_jkt all pass, the client registered itself: open registration, CIMD or a developer account, the request carries the cookie of a live browser session of an enabled user, the consent step cannot show the scopes: more than 64, or one outside its alphabet (RFC 6749 §3.3 without < and >) or over 128 characters; read only when an interaction asks for consent, it carries no prompt, or prompt=login, prompt=consent or prompt=create, the request carries no prompt=create, nothing asks for a fresh sign-in, or the sign-in is fresh enough for what asks, no stored consent covers the request, prompt=consent asks for the screen, the request widens a prior grant, or the client is an AI agent, which never skips the screen (ADR-015 Decision 11), the client and its redirect URI still pass when the interaction finishes or is cancelled, the session the interaction holds is live and its account may use it, when the request is decided again
  1. Wait for an authorization request: GET /oauth/authorize arrives with its parameters in the query, or POST with them in a form
  2. Find the realm of the host: the request has its realm
  3. Count the request against the authorize limit: the address is under its limit
  4. Check the parameters against the authorize schema: the parameters match the schema
  5. Find the client: the client is found
  6. Check the redirect URI against the client's registration: redirect_uri is registered
  7. Check the redirect URI against the environment policy: the environment permits the redirect URI
  8. Check that the client may use the endpoint: the client may use the endpoint
  9. Read the DPoP key the code is to be bound to: dpop_jkt is absent, unread or well formed
  10. Check a request for a registration: the request carries no prompt=create
  11. Find the browser session: the session is live
  12. Refuse an agent scope above the client's cap: no agent scope is above the cap; the scopes are the requested ones the client's allowlist holds
  13. Refuse a QAuth API audience the client does not list: every QAuth API audience among the resources is one the client lists
  14. Read the consent, and decide whether the sign-in is fresh enough and the consent covers the request: no consent covers the request: the person is asked
  15. Send the person to consent: the consent step cannot show the scopes, for a client no operator provisioned
Tell the client the consent step cannot show its resources
redirect, error=invalid_target
INTERACTION_UI_ENABLED is on: the sign-in and the consent are interactions (#628), the host is the primary host of an enabled realm, the address is under its limit, the parameters pass the route schema, and the client, its redirect URI, its grant and response type and dpop_jkt all pass, an operator provisioned the client (provisioned_by_operator): the system client or the seed manifest, the request carries the cookie of a live browser session of an enabled user, the consent step cannot show the resources: more than 16, or one over 2048 characters; read only when an interaction asks for consent, it carries no prompt, or prompt=login, prompt=consent or prompt=create, the request carries no prompt=create, nothing asks for a fresh sign-in, or the sign-in is fresh enough for what asks, no stored consent covers the request, prompt=consent asks for the screen, the request widens a prior grant, or the client is an AI agent, which never skips the screen (ADR-015 Decision 11), the client and its redirect URI still pass when the interaction finishes or is cancelled, the session the interaction holds is live and its account may use it, when the request is decided again
  1. Wait for an authorization request: GET /oauth/authorize arrives with its parameters in the query, or POST with them in a form
  2. Find the realm of the host: the request has its realm
  3. Count the request against the authorize limit: the address is under its limit
  4. Check the parameters against the authorize schema: the parameters match the schema
  5. Find the client: the client is found
  6. Check the redirect URI against the client's registration: redirect_uri is registered
  7. Check the redirect URI against the environment policy: the environment permits the redirect URI
  8. Check that the client may use the endpoint: the client may use the endpoint
  9. Read the DPoP key the code is to be bound to: dpop_jkt is absent, unread or well formed
  10. Check a request for a registration: the request carries no prompt=create
  11. Find the browser session: the session is live
  12. Refuse an agent scope above the client's cap: no agent scope is above the cap; the scopes are the requested ones the client's allowlist holds
  13. Refuse a QAuth API audience the client does not list: every QAuth API audience among the resources is one the client lists
  14. Read the consent, and decide whether the sign-in is fresh enough and the consent covers the request: no consent covers the request: the person is asked
  15. Send the person to consent: the consent step cannot show the resources, for a client an operator provisioned
Show, rather than redirect, that error for a client no operator provisioned
no redirect, page shown
INTERACTION_UI_ENABLED is on: the sign-in and the consent are interactions (#628), the host is the primary host of an enabled realm, the address is under its limit, the parameters pass the route schema, and the client, its redirect URI, its grant and response type and dpop_jkt all pass, the client registered itself: open registration, CIMD or a developer account, the request carries the cookie of a live browser session of an enabled user, the consent step cannot show the resources: more than 16, or one over 2048 characters; read only when an interaction asks for consent, it carries no prompt, or prompt=login, prompt=consent or prompt=create, the request carries no prompt=create, nothing asks for a fresh sign-in, or the sign-in is fresh enough for what asks, no stored consent covers the request, prompt=consent asks for the screen, the request widens a prior grant, or the client is an AI agent, which never skips the screen (ADR-015 Decision 11), the client and its redirect URI still pass when the interaction finishes or is cancelled, the session the interaction holds is live and its account may use it, when the request is decided again
  1. Wait for an authorization request: GET /oauth/authorize arrives with its parameters in the query, or POST with them in a form
  2. Find the realm of the host: the request has its realm
  3. Count the request against the authorize limit: the address is under its limit
  4. Check the parameters against the authorize schema: the parameters match the schema
  5. Find the client: the client is found
  6. Check the redirect URI against the client's registration: redirect_uri is registered
  7. Check the redirect URI against the environment policy: the environment permits the redirect URI
  8. Check that the client may use the endpoint: the client may use the endpoint
  9. Read the DPoP key the code is to be bound to: dpop_jkt is absent, unread or well formed
  10. Check a request for a registration: the request carries no prompt=create
  11. Find the browser session: the session is live
  12. Refuse an agent scope above the client's cap: no agent scope is above the cap; the scopes are the requested ones the client's allowlist holds
  13. Refuse a QAuth API audience the client does not list: every QAuth API audience among the resources is one the client lists
  14. Read the consent, and decide whether the sign-in is fresh enough and the consent covers the request: no consent covers the request: the person is asked
  15. Send the person to consent: the consent step cannot show the resources, for a client no operator provisioned
Refuse parameters the schema does not accept
no redirect, page shown
INTERACTION_UI_ENABLED is off, the default: the sign-in and the consent are the server-rendered pages, the query (GET) or the form (POST) does not pass authorizeQuerySchema: a missing or malformed code_challenge, a code_challenge_method other than S256, a response_type other than code, a state or nonce over 2048 characters, a login_hint over 254 bytes, a resource that is not an absolute URI, an operator provisioned the client (provisioned_by_operator): the system client or the seed manifest, the request carries the cookie of a live browser session of an enabled user, nothing in the request is refused after the session, it carries no prompt, or prompt=login, prompt=consent or prompt=create, the request carries no prompt=create, nothing asks for a fresh sign-in, or the sign-in is fresh enough for what asks, a stored consent covers every requested scope at each requested resource, or the client's administrative consent does (ADR-017 Decision 9), and nothing asks for the screen, the client and its redirect URI still pass when the interaction finishes or is cancelled, the session the interaction holds is live and its account may use it, when the request is decided again
  1. Wait for an authorization request: GET /oauth/authorize arrives with its parameters in the query, or POST with them in a form
  2. Find the realm of the host: the request has its realm
  3. Count the request against the authorize limit: the address is under its limit
  4. Check the parameters against the authorize schema: the parameters do not match the schema
Refuse a client_id that names no client
no redirect, page shown
INTERACTION_UI_ENABLED is off, the default: the sign-in and the consent are the server-rendered pages, client_id names no client of the realm, or a CIMD document that does not resolve, an operator provisioned the client (provisioned_by_operator): the system client or the seed manifest, the request carries the cookie of a live browser session of an enabled user, nothing in the request is refused after the session, it carries no prompt, or prompt=login, prompt=consent or prompt=create, the request carries no prompt=create, nothing asks for a fresh sign-in, or the sign-in is fresh enough for what asks, a stored consent covers every requested scope at each requested resource, or the client's administrative consent does (ADR-017 Decision 9), and nothing asks for the screen, the client and its redirect URI still pass when the interaction finishes or is cancelled, the session the interaction holds is live and its account may use it, when the request is decided again
  1. Wait for an authorization request: GET /oauth/authorize arrives with its parameters in the query, or POST with them in a form
  2. Find the realm of the host: the request has its realm
  3. Count the request against the authorize limit: the address is under its limit
  4. Check the parameters against the authorize schema: the parameters match the schema
  5. Find the client: the client_id names no client of the realm
Refuse a redirect URI the client did not register
no redirect, page shown
INTERACTION_UI_ENABLED is off, the default: the sign-in and the consent are the server-rendered pages, redirect_uri is none of the client's (a loopback URI may differ only in its port), an operator provisioned the client (provisioned_by_operator): the system client or the seed manifest, the request carries the cookie of a live browser session of an enabled user, nothing in the request is refused after the session, it carries no prompt, or prompt=login, prompt=consent or prompt=create, the request carries no prompt=create, nothing asks for a fresh sign-in, or the sign-in is fresh enough for what asks, a stored consent covers every requested scope at each requested resource, or the client's administrative consent does (ADR-017 Decision 9), and nothing asks for the screen, the client and its redirect URI still pass when the interaction finishes or is cancelled, the session the interaction holds is live and its account may use it, when the request is decided again
  1. Wait for an authorization request: GET /oauth/authorize arrives with its parameters in the query, or POST with them in a form
  2. Find the realm of the host: the request has its realm
  3. Count the request against the authorize limit: the address is under its limit
  4. Check the parameters against the authorize schema: the parameters match the schema
  5. Find the client: the client is found
  6. Check the redirect URI against the client's registration: redirect_uri is not registered for the client
Refuse a redirect URI no environment permits
no redirect, page shown
INTERACTION_UI_ENABLED is off, the default: the sign-in and the consent are the server-rendered pages, redirect_uri is the client's, but no environment permits it: a scheme outside the allowed ones, plain http to a host that is not loopback, or http to localhost outside development, an operator provisioned the client (provisioned_by_operator): the system client or the seed manifest, the request carries the cookie of a live browser session of an enabled user, nothing in the request is refused after the session, it carries no prompt, or prompt=login, prompt=consent or prompt=create, the request carries no prompt=create, nothing asks for a fresh sign-in, or the sign-in is fresh enough for what asks, a stored consent covers every requested scope at each requested resource, or the client's administrative consent does (ADR-017 Decision 9), and nothing asks for the screen, the client and its redirect URI still pass when the interaction finishes or is cancelled, the session the interaction holds is live and its account may use it, when the request is decided again
  1. Wait for an authorization request: GET /oauth/authorize arrives with its parameters in the query, or POST with them in a form
  2. Find the realm of the host: the request has its realm
  3. Count the request against the authorize limit: the address is under its limit
  4. Check the parameters against the authorize schema: the parameters match the schema
  5. Find the client: the client is found
  6. Check the redirect URI against the client's registration: redirect_uri is registered
  7. Check the redirect URI against the environment policy: no environment permits that redirect_uri
Refuse a disabled or suspended client
no redirect, page shown
INTERACTION_UI_ENABLED is off, the default: the sign-in and the consent are the server-rendered pages, the client is disabled or suspended, an operator provisioned the client (provisioned_by_operator): the system client or the seed manifest, the request carries the cookie of a live browser session of an enabled user, nothing in the request is refused after the session, it carries no prompt, or prompt=login, prompt=consent or prompt=create, the request carries no prompt=create, nothing asks for a fresh sign-in, or the sign-in is fresh enough for what asks, a stored consent covers every requested scope at each requested resource, or the client's administrative consent does (ADR-017 Decision 9), and nothing asks for the screen, the client and its redirect URI still pass when the interaction finishes or is cancelled, the session the interaction holds is live and its account may use it, when the request is decided again
  1. Wait for an authorization request: GET /oauth/authorize arrives with its parameters in the query, or POST with them in a form
  2. Find the realm of the host: the request has its realm
  3. Count the request against the authorize limit: the address is under its limit
  4. Check the parameters against the authorize schema: the parameters match the schema
  5. Find the client: the client is found
  6. Check the redirect URI against the client's registration: redirect_uri is registered
  7. Check the redirect URI against the environment policy: the environment permits the redirect URI
  8. Check that the client may use the endpoint: the client is disabled or suspended
Refuse a client not registered for the authorization_code grant
no redirect, page shown
INTERACTION_UI_ENABLED is off, the default: the sign-in and the consent are the server-rendered pages, the client is not registered for the authorization_code grant, an operator provisioned the client (provisioned_by_operator): the system client or the seed manifest, the request carries the cookie of a live browser session of an enabled user, nothing in the request is refused after the session, it carries no prompt, or prompt=login, prompt=consent or prompt=create, the request carries no prompt=create, nothing asks for a fresh sign-in, or the sign-in is fresh enough for what asks, a stored consent covers every requested scope at each requested resource, or the client's administrative consent does (ADR-017 Decision 9), and nothing asks for the screen, the client and its redirect URI still pass when the interaction finishes or is cancelled, the session the interaction holds is live and its account may use it, when the request is decided again
  1. Wait for an authorization request: GET /oauth/authorize arrives with its parameters in the query, or POST with them in a form
  2. Find the realm of the host: the request has its realm
  3. Count the request against the authorize limit: the address is under its limit
  4. Check the parameters against the authorize schema: the parameters match the schema
  5. Find the client: the client is found
  6. Check the redirect URI against the client's registration: redirect_uri is registered
  7. Check the redirect URI against the environment policy: the environment permits the redirect URI
  8. Check that the client may use the endpoint: the client is not registered for the authorization_code grant
Refuse a client not registered for the code response type
no redirect, page shown
INTERACTION_UI_ENABLED is off, the default: the sign-in and the consent are the server-rendered pages, the client is not registered for the code response type, an operator provisioned the client (provisioned_by_operator): the system client or the seed manifest, the request carries the cookie of a live browser session of an enabled user, nothing in the request is refused after the session, it carries no prompt, or prompt=login, prompt=consent or prompt=create, the request carries no prompt=create, nothing asks for a fresh sign-in, or the sign-in is fresh enough for what asks, a stored consent covers every requested scope at each requested resource, or the client's administrative consent does (ADR-017 Decision 9), and nothing asks for the screen, the client and its redirect URI still pass when the interaction finishes or is cancelled, the session the interaction holds is live and its account may use it, when the request is decided again
  1. Wait for an authorization request: GET /oauth/authorize arrives with its parameters in the query, or POST with them in a form
  2. Find the realm of the host: the request has its realm
  3. Count the request against the authorize limit: the address is under its limit
  4. Check the parameters against the authorize schema: the parameters match the schema
  5. Find the client: the client is found
  6. Check the redirect URI against the client's registration: redirect_uri is registered
  7. Check the redirect URI against the environment policy: the environment permits the redirect URI
  8. Check that the client may use the endpoint: the client is not registered for the code response type
Refuse a request too large to hold through the sign-in or the consent
no redirect, page shown
INTERACTION_UI_ENABLED is on: the sign-in and the consent are interactions (#628), the host is the primary host of an enabled realm, the address is under its limit, the parameters pass the route schema, and the client, its redirect URI, its grant and response type and dpop_jkt all pass, an operator provisioned the client (provisioned_by_operator): the system client or the seed manifest, the request carries the cookie of a live browser session of an enabled user, nothing in the request is refused after the session, it carries no prompt, or prompt=login, prompt=consent or prompt=create, prompt=create with openid and no max_age, the realm and the client allowing sign-up, nothing asks for a fresh sign-in, or the sign-in is fresh enough for what asks, a stored consent covers every requested scope at each requested resource, or the client's administrative consent does (ADR-017 Decision 9), and nothing asks for the screen, the client and its redirect URI still pass when the interaction finishes or is cancelled, the session the interaction holds is live and its account may use it, when the request is decided again
  1. Wait for an authorization request: GET /oauth/authorize arrives with its parameters in the query, or POST with them in a form
  2. Find the realm of the host: the request has its realm
  3. Count the request against the authorize limit: the address is under its limit
  4. Check the parameters against the authorize schema: the parameters match the schema
  5. Find the client: the client is found
  6. Check the redirect URI against the client's registration: redirect_uri is registered
  7. Check the redirect URI against the environment policy: the environment permits the redirect URI
  8. Check that the client may use the endpoint: the client may use the endpoint
  9. Read the DPoP key the code is to be bound to: dpop_jkt is absent, unread or well formed
  10. Check a request for a registration: the registration is allowed
  11. Start a registration interaction: it fails, because the request is over 16 KiB, or the record over 32 KiB
Refuse a host this server does not answer for here
no redirect, page shown
INTERACTION_UI_ENABLED is off, the default: the sign-in and the consent are the server-rendered pages, the host names no realm, a disabled realm or a realm with no issuer, or it is one of the realm's endpoint hosts, which serve no browser route, an operator provisioned the client (provisioned_by_operator): the system client or the seed manifest, the request carries the cookie of a live browser session of an enabled user, nothing in the request is refused after the session, it carries no prompt, or prompt=login, prompt=consent or prompt=create, the request carries no prompt=create, nothing asks for a fresh sign-in, or the sign-in is fresh enough for what asks, a stored consent covers every requested scope at each requested resource, or the client's administrative consent does (ADR-017 Decision 9), and nothing asks for the screen, the client and its redirect URI still pass when the interaction finishes or is cancelled, the session the interaction holds is live and its account may use it, when the request is decided again
  1. Wait for an authorization request: GET /oauth/authorize arrives with its parameters in the query, or POST with them in a form
  2. Find the realm of the host: the host names no enabled realm with an issuer, or is one of its endpoint hosts
Refuse an address over the authorize limit
no redirect, page shown
INTERACTION_UI_ENABLED is off, the default: the sign-in and the consent are the server-rendered pages, the address has used up its AUTHORIZE_RATE_LIMIT requests for the window, an operator provisioned the client (provisioned_by_operator): the system client or the seed manifest, the request carries the cookie of a live browser session of an enabled user, nothing in the request is refused after the session, it carries no prompt, or prompt=login, prompt=consent or prompt=create, the request carries no prompt=create, nothing asks for a fresh sign-in, or the sign-in is fresh enough for what asks, a stored consent covers every requested scope at each requested resource, or the client's administrative consent does (ADR-017 Decision 9), and nothing asks for the screen, the client and its redirect URI still pass when the interaction finishes or is cancelled, the session the interaction holds is live and its account may use it, when the request is decided again
  1. Wait for an authorization request: GET /oauth/authorize arrives with its parameters in the query, or POST with them in a form
  2. Find the realm of the host: the request has its realm
  3. Count the request against the authorize limit: the address has used up its requests
Fail a request whose session cookie cannot be decoded
no redirect, page shown
INTERACTION_UI_ENABLED is on: the sign-in and the consent are interactions (#628), the host is the primary host of an enabled realm, the address is under its limit, the parameters pass the route schema, and the client, its redirect URI, its grant and response type and dpop_jkt all pass, an operator provisioned the client (provisioned_by_operator): the system client or the seed manifest, the session cookie's value is not valid percent-encoding, such as %zz, which the cookie reader decodes without a catch, nothing in the request is refused after the session, it carries no prompt, or prompt=login, prompt=consent or prompt=create, prompt=create with openid and no max_age, the realm and the client allowing sign-up, nothing asks for a fresh sign-in, or the sign-in is fresh enough for what asks, a stored consent covers every requested scope at each requested resource, or the client's administrative consent does (ADR-017 Decision 9), and nothing asks for the screen, the client and its redirect URI still pass when the interaction finishes or is cancelled, the session the interaction holds is live and its account may use it, when the request is decided again
  1. Wait for an authorization request: GET /oauth/authorize arrives with its parameters in the query, or POST with them in a form
  2. Find the realm of the host: the request has its realm
  3. Count the request against the authorize limit: the address is under its limit
  4. Check the parameters against the authorize schema: the parameters match the schema
  5. Find the client: the client is found
  6. Check the redirect URI against the client's registration: redirect_uri is registered
  7. Check the redirect URI against the environment policy: the environment permits the redirect URI
  8. Check that the client may use the endpoint: the client may use the endpoint
  9. Read the DPoP key the code is to be bound to: dpop_jkt is absent, unread or well formed
  10. Check a request for a registration: the session cookie cannot be decoded
Fail the request when the database fails at the mint
no redirect, page shown
INTERACTION_UI_ENABLED is off, the default: the sign-in and the consent are the server-rendered pages, the host is the primary host of an enabled realm, the address is under its limit, the parameters pass the route schema, and the client, its redirect URI, its grant and response type and dpop_jkt all pass, an operator provisioned the client (provisioned_by_operator): the system client or the seed manifest, the request carries the cookie of a live browser session of an enabled user, nothing in the request is refused after the session, it carries no prompt, or prompt=login, prompt=consent or prompt=create, the request carries no prompt=create, nothing asks for a fresh sign-in, or the sign-in is fresh enough for what asks, a stored consent covers every requested scope at each requested resource, or the client's administrative consent does (ADR-017 Decision 9), and nothing asks for the screen, the client and its redirect URI still pass when the interaction finishes or is cancelled, the session the interaction holds is live and its account may use it, when the request is decided again
  1. Wait for an authorization request: GET /oauth/authorize arrives with its parameters in the query, or POST with them in a form
  2. Find the realm of the host: the request has its realm
  3. Count the request against the authorize limit: the address is under its limit
  4. Check the parameters against the authorize schema: the parameters match the schema
  5. Find the client: the client is found
  6. Check the redirect URI against the client's registration: redirect_uri is registered
  7. Check the redirect URI against the environment policy: the environment permits the redirect URI
  8. Check that the client may use the endpoint: the client may use the endpoint
  9. Read the DPoP key the code is to be bound to: dpop_jkt is absent, unread or well formed
  10. Check a request for a registration: the request carries no prompt=create
  11. Find the browser session: the session is live
  12. Refuse an agent scope above the client's cap: no agent scope is above the cap; the scopes are the requested ones the client's allowlist holds
  13. Refuse a QAuth API audience the client does not list: every QAuth API audience among the resources is one the client lists
  14. Read the consent, and decide whether the sign-in is fresh enough and the consent covers the request: the sign-in is fresh enough and a consent covers the request
  15. Mint the authorization code under the consent and the session: it fails, because the database fails
Fail the request when the interaction store fails
no redirect, page shown
INTERACTION_UI_ENABLED is on: the sign-in and the consent are interactions (#628), the host is the primary host of an enabled realm, the address is under its limit, the parameters pass the route schema, and the client, its redirect URI, its grant and response type and dpop_jkt all pass, an operator provisioned the client (provisioned_by_operator): the system client or the seed manifest, the request carries the cookie of a live browser session of an enabled user, nothing in the request is refused after the session, it carries no prompt, or prompt=login, prompt=consent or prompt=create, prompt=create with openid and no max_age, the realm and the client allowing sign-up, nothing asks for a fresh sign-in, or the sign-in is fresh enough for what asks, a stored consent covers every requested scope at each requested resource, or the client's administrative consent does (ADR-017 Decision 9), and nothing asks for the screen, the client and its redirect URI still pass when the interaction finishes or is cancelled, the session the interaction holds is live and its account may use it, when the request is decided again
  1. Wait for an authorization request: GET /oauth/authorize arrives with its parameters in the query, or POST with them in a form
  2. Find the realm of the host: the request has its realm
  3. Count the request against the authorize limit: the address is under its limit
  4. Check the parameters against the authorize schema: the parameters match the schema
  5. Find the client: the client is found
  6. Check the redirect URI against the client's registration: redirect_uri is registered
  7. Check the redirect URI against the environment policy: the environment permits the redirect URI
  8. Check that the client may use the endpoint: the client may use the endpoint
  9. Read the DPoP key the code is to be bound to: dpop_jkt is absent, unread or well formed
  10. Check a request for a registration: the registration is allowed
  11. Start a registration interaction: it fails, because the interaction store fails

Each row is also a generated test: set the starting situation, send the events, expect the ending.

What is guaranteed

These hold in all 2162908 situations the model can reach, from 253440 different starting situations.

Exact rules
IdNever
interaction-only-for-a-checked-requestinteractionStarted and gate != 'open'
pages-start-no-interactioninteractionStarted and pages
interactions-park-nothingstate in ['parkingRequest', 'consent_screen.page', 'consent_screen.consent_withdrawn'] and not pages
prompt-none-shows-nothingsilent and (interactionStarted or state in ['parkingRequest', 'consent_screen.page', 'consent_screen.consent_withdrawn', 'atSignInCeremony', 'atConsentCeremony'])
no-code-while-an-interaction-is-opencodeMinted and interactionOpen
no-code-without-consentcodeMinted and consentMissing
no-code-on-a-stale-sign-incodeMinted and needsFreshLogin
no-code-for-a-refused-requestcodeMinted and (overAgentCap or audienceUnlisted or (finishing and since != 'unchanged'))
shown-not-redirected-before-any-pageprovisioning == 'selfService' and state in ['invalid_request.malformed_dpop_jkt', 'login_required.no_session', 'invalid_request.create_without_openid', 'invalid_request.registration_not_offered', 'unauthorized_client.registration_not_allowed', 'invalid_request.create_with_max_age', 'invalid_scope.agent_scope_mode_exceeded', 'invalid_target.unlisted_reserved_audience', 'login_required.fresh_login', 'consent_required.prompt_none', 'login_required.session_ended', 'consent_required.consent_withdrawn', 'invalid_scope.consent_not_shown', 'invalid_target.consent_not_shown']
a-finish-only-from-an-interactionphase == 'finish' and not interactionStarted
registration-only-when-allowedstate in ['startingRegistration', 'atRegistrationCeremony'] and create != 'allowed'

Reference

All transitions (113)
FromEventGuardToEffectsTaken
idleAUTHORIZEresolvingRealmyes
idleREPLAYinteraction_expired.finishedyes
resolvingRealmrule 1hostUnknownmisdirected_request.hostyes
resolvingRealmrule 2rateLimitingyes
rateLimitingrule 1rateLimitedtoo_many_requests.authorize_limityes
rateLimitingrule 2validatingParametersyes
validatingParametersrule 1inputInvalidinvalid_request.schemayes
validatingParametersrule 2resolvingClientyes
resolvingClientrule 1clientUnknowninvalid_request.unknown_clientyes
resolvingClientrule 2checkingRedirectUriyes
checkingRedirectUrirule 1redirectUnregisteredinvalid_request.redirect_uri_not_registeredyes
checkingRedirectUrirule 2checkingEnvironmentyes
checkingEnvironmentrule 1redirectNotPermittedinvalid_request.redirect_uri_not_permittedyes
checkingEnvironmentrule 2checkingClientGrantyes
checkingClientGrantrule 1clientDisabledunauthorized_client.disabledyes
checkingClientGrantrule 2noCodeGrantunauthorized_client.grant_typeyes
checkingClientGrantrule 3noCodeResponseunauthorized_client.response_typeyes
checkingClientGrantrule 4readingDpopKeyyes
readingDpopKeyrule 1dpopJktMalformed and operatorClientinvalid_request.malformed_dpop_jktyes
readingDpopKeyrule 2dpopJktMalformedinvalid_request.malformed_dpop_jkt_shownyes
readingDpopKeyrule 3checkingCreatePromptyes
checkingCreatePromptrule 1create == 'absent' or silentfindingSessionyes
checkingCreatePromptrule 2create == 'withoutOpenid' and operatorClientinvalid_request.create_without_openidyes
checkingCreatePromptrule 3create == 'withoutOpenid'invalid_request.create_without_openid_shownyes
checkingCreatePromptrule 4(create == 'notOffered' or pages) and operatorClientinvalid_request.registration_not_offeredyes
checkingCreatePromptrule 5create == 'notOffered' or pagesinvalid_request.registration_not_offered_shownyes
checkingCreatePromptrule 6create == 'clientNotAllowed' and operatorClientunauthorized_client.registration_not_allowedyes
checkingCreatePromptrule 7create == 'clientNotAllowed'unauthorized_client.registration_not_allowed_shownyes
checkingCreatePromptrule 8create == 'withMaxAge' and operatorClientinvalid_request.create_with_max_ageyes
checkingCreatePromptrule 9create == 'withMaxAge'invalid_request.create_with_max_age_shownyes
checkingCreatePromptrule 10cookieMalformedserver_error.malformed_cookieyes
checkingCreatePromptrule 11startingRegistrationyes
startingRegistrationDONEatRegistrationCeremonyopenInteractionyes
startingRegistrationFAIL.tooLargeinvalid_request.authorization_too_largeyes
startingRegistrationFAIL.serverserver_error.interaction_storeyes
atRegistrationCeremonyFINISHtakingFinishfinishRegistrationyes
atRegistrationCeremonyCANCELrecheckingCancelyes
findingSessionrule 1cookieMalformedserver_error.malformed_cookieyes
findingSessionrule 2(noSession or unusableSession) and silent and operatorClientlogin_required.no_sessionyes
findingSessionrule 3(noSession or unusableSession) and silentlogin_required.no_session_shownyes
findingSessionrule 4noSession or unusableSessionsignInNeededyes
findingSessionrule 5checkingAgentCapyes
checkingAgentCaprule 1overAgentCap and finishinginvalid_scope.agent_scope_mode_exceeded_after_sign_inyes
checkingAgentCaprule 2overAgentCap and operatorClientinvalid_scope.agent_scope_mode_exceededyes
checkingAgentCaprule 3overAgentCapinvalid_scope.agent_scope_mode_exceeded_shownyes
checkingAgentCaprule 4checkingAudienceyes
checkingAudiencerule 1audienceUnlisted and finishinginvalid_target.unlisted_reserved_audience_after_sign_inyes
checkingAudiencerule 2audienceUnlisted and operatorClientinvalid_target.unlisted_reserved_audienceyes
checkingAudiencerule 3audienceUnlistedinvalid_target.unlisted_reserved_audience_shownyes
checkingAudiencerule 4decidingStepUpyes
decidingStepUprule 1silent and needsFreshLogin and operatorClientlogin_required.fresh_loginyes
decidingStepUprule 2silent and needsFreshLoginlogin_required.fresh_login_shownyes
decidingStepUprule 3silent and consentMissing and operatorClientconsent_required.prompt_noneyes
decidingStepUprule 4silent and consentMissingconsent_required.prompt_none_shownyes
decidingStepUprule 5needsFreshLoginsignInNeededforFreshLoginyes
decidingStepUprule 6consentMissingconsentNeededyes
decidingStepUprule 7mintingCodeyes
mintingCodeDONEfinishingcode_issued.after_sign_inmintCodeyes
mintingCodeDONEcode_issuedmintCodeyes
mintingCodeFAIL.sessionEndedsilent and operatorClientlogin_required.session_endedyes
mintingCodeFAIL.sessionEndedsilentlogin_required.session_ended_shownyes
mintingCodeFAIL.sessionEndedsignInNeededforEndedSessionyes
mintingCodeFAIL.consentWithdrawnsilent and operatorClientconsent_required.consent_withdrawnyes
mintingCodeFAIL.consentWithdrawnsilentconsent_required.consent_withdrawn_shownyes
mintingCodeFAIL.consentWithdrawnconsentNeededforWithdrawnConsentyes
mintingCodeFAIL.serverfinishingserver_error.store_after_sign_inyes
mintingCodeFAIL.serverserver_error.storeyes
signInNeededrule 1finishingcontinuingToSignInyes
signInNeededrule 2pagesparkingRequestyes
signInNeededrule 3startingSignInyes
consentNeededrule 1pages and consentCause == 'withdrawn'consent_screen.consent_withdrawnyes
consentNeededrule 2pagesconsent_screen.pageyes
consentNeededrule 3scopesUnshowable and finishinginvalid_scope.consent_not_shown_after_sign_inyes
consentNeededrule 4resourcesUnshowable and finishinginvalid_target.consent_not_shown_after_sign_inyes
consentNeededrule 5scopesUnshowable and operatorClientinvalid_scope.consent_not_shownyes
consentNeededrule 6scopesUnshowableinvalid_scope.consent_not_shown_shownyes
consentNeededrule 7resourcesUnshowable and operatorClientinvalid_target.consent_not_shownyes
consentNeededrule 8resourcesUnshowableinvalid_target.consent_not_shown_shownyes
consentNeededrule 9finishingcontinuingToConsentyes
consentNeededrule 10startingConsentyes
parkingRequestDONEnoSessionsign_in_required.no_sessionyes
parkingRequestDONEunusableSessionsign_in_required.unusable_sessionyes
parkingRequestDONEsignInCause == 'sessionEnded'sign_in_required.session_endedyes
parkingRequestDONEsign_in_required.fresh_loginyes
parkingRequestFAIL.tooLargeinvalid_request.authorization_too_largeyes
startingSignInDONEatSignInCeremonyopenInteractionyes
startingSignInFAIL.tooLargeinvalid_request.authorization_too_largeyes
startingSignInFAIL.serverserver_error.interaction_storeyes
startingConsentDONEatConsentCeremonyopenInteractionyes
startingConsentFAIL.tooLargeinvalid_request.authorization_too_largeyes
startingConsentFAIL.serverserver_error.interaction_storeyes
atSignInCeremonyFINISHtakingFinishfinishInteractionyes
atSignInCeremonyCANCELrecheckingCancelyes
atConsentCeremonyANSWERconsent_step.answeredyes
atConsentCeremonyCANCELrecheckingCancelyes
recheckingCancelrule 1since == 'clientGone'invalid_request.client_changedyes
recheckingCancelrule 2since == 'clientUnusable'unauthorized_client.client_changedyes
recheckingCancelrule 3access_denied.cancelledyes
takingFinishDONErecheckingRequestyes
takingFinishFAIL.expiredinteraction_expired.finished_lateyes
takingFinishFAIL.sessionEndedinteraction_expired.session_endedyes
takingFinishFAIL.serverserver_error.interaction_store_after_sign_inyes
recheckingRequestrule 1since == 'clientGone'invalid_request.client_changedyes
recheckingRequestrule 2since == 'clientUnusable'unauthorized_client.client_changedyes
recheckingRequestrule 3findingTransactionSessionyes
findingTransactionSessionrule 1finishSession == 'unusable'signInNeededforEndedSessionyes
findingTransactionSessionrule 2checkingAgentCapyes
continuingToSignInDONEatSignInCeremonyopenInteractionyes
continuingToSignInFAIL.tooLargeinvalid_request.authorization_too_large_after_sign_inyes
continuingToSignInFAIL.serverserver_error.interaction_store_after_sign_inyes
continuingToConsentDONEatConsentCeremonyopenInteractionyes
continuingToConsentFAIL.tooLargeinvalid_request.authorization_too_large_after_sign_inyes
continuingToConsentFAIL.serverserver_error.interaction_store_after_sign_inyes