OAuth2 Consent Screen
The consent screen allows users to review and approve the scopes an OAuth2 client is requesting before an authorization code is issued. Consent is per-client and per-user – once granted, it is remembered and not re-prompted unless scopes change.
Consent flow
Section titled “Consent flow”sequenceDiagram
actor User
participant Browser
participant IdP as Autentico
User->>Browser: Complete login (password / passkey / MFA)
Browser->>IdP: POST /oauth2/login
IdP->>IdP: Authentication successful
IdP->>Browser: 302 -> /oauth2/consent?client_id=X&scope=Y&...
Browser->>IdP: GET /oauth2/consent (render consent page)
IdP->>Browser: Show requested scopes + Allow / Deny buttons
User->>Browser: Click "Allow"
Browser->>IdP: POST /oauth2/consent (action=allow)
IdP->>IdP: Store consent in user_consents table
IdP->>Browser: 302 -> redirect_uri?code=AUTH_CODE
If the user clicks Deny, Autentico redirects back to the client with error=access_denied per RFC 6749 Section 4.1.2.1.
Enabling consent for a client
Section titled “Enabling consent for a client”Consent is controlled by the consent_required field on the client. When consent_required is true, users must approve scopes before an authorization code is issued.
Set it when creating or updating a client:
curl -X POST https://auth.example.com/admin/api/clients \ -H "Authorization: Bearer $ADMIN_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "client_id": "my-app", "client_name": "My Application", "redirect_uris": ["https://app.example.com/callback"], "grant_types": ["authorization_code", "refresh_token"], "response_types": ["code"], "scopes": "openid profile email offline_access", "client_type": "public", "token_endpoint_auth_method": "none", "consent_required": true }'When consent_required is false or not set, consent is skipped after authentication unless the request includes prompt=consent. That prompt requires an explicit decision even for a first-party client.
Scope descriptions
Section titled “Scope descriptions”The consent screen displays human-readable descriptions for standard scopes:
| Scope | Description shown to user |
|---|---|
openid |
Verify your identity |
profile |
View your profile information |
email |
View your email address |
address |
View your address |
phone |
View your phone number |
offline_access |
Stay signed in between sessions |
Custom scopes are displayed by their raw scope name.
Consent persistence
Section titled “Consent persistence”When a user approves a consent request, the decision is stored in the user_consents table with the following fields:
| Column | Description |
|---|---|
id |
Unique consent record ID |
user_id |
The user who granted consent |
client_id |
The client that received consent |
scopes |
Space-separated list of approved scopes |
granted_at |
Timestamp of when consent was granted |
A unique constraint on (user_id, client_id) ensures only one consent record exists per user-client pair. When a user re-approves, the existing record is updated with the new scopes and timestamp.
When re-consent is triggered
Section titled “When re-consent is triggered”Autentico skips the consent screen if all of these conditions are true:
- The user has a stored consent record for the client
- All requested scopes are covered by the previously granted scopes
- The
promptparameter does not includeconsent
Re-consent is triggered when:
- New scopes are requested – if the client requests a scope not covered by the stored consent, the user is re-prompted
prompt=consent– per OIDC Core Section 3.1.2.1, theprompt=consentparameter forces re-prompting even if consent was previously granted- No prior consent exists – the user has never approved scopes for this client
Security
Section titled “Security”Consent URLs are internal continuations issued after successful login or eligible SSO. A signed consent_flow binds the exact authorization parameters to the browser session for ten minutes. An old session cookie and arbitrary GET parameters cannot create a new consent request. Applications should begin at /oauth2/authorize.
Opening and submitting consent recheck current client status, redirect URI, code flow, scopes and PKCE, along with active user status, local MFA, the current client idle timeout, global session lifetime and any positive max_age. An expired login or continuation requires restarting authorization.
Fresh login can continue to consent with SSO disabled or prompt=login / max_age=0. An SSO continuation cannot substitute for fresh login. prompt=none never opens consent: it returns login_required when authentication is needed, or consent_required when an eligible session needs approval.
The form’s HMAC-SHA256 consent_sig covers every authorization field, including prompt, max_age, continuation and user ID. Submission requires an explicit Allow or Deny action. Changing parameters or browser sessions invalidates the continuation.
Token auth_time reflects actual browser authentication, including after waiting on consent or using SSO. Code exchange and token refreshes preserve that time; issuing a token does not authenticate the user again.