spring-projects/spring-security · error · OAuth2AuthorizationCodeRequestAuthenticationException

consent_required

consent_required

Error message

OAuth 2.0 Parameter: prompt

What it means

This error is thrown by the authorization code request provider when user consent is required to proceed, but the original authorization request contained prompt=none. Per OIDC, the server must not display any UI for prompt=none, so instead of rendering the consent page it returns an OAuth2 error consent_required attributed to the prompt parameter. It signals that silent authentication could not complete because the client has not yet been granted consent for the requested scopes.

Source

Thrown at oauth2/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthorizationCodeRequestAuthenticationProvider.java:266

			.authorizationUri(authorizationCodeRequestAuthentication.getAuthorizationUri())
			.clientId(registeredClient.getClientId())
			.redirectUri(authorizationCodeRequestAuthentication.getRedirectUri())
			.scopes(authorizationCodeRequestAuthentication.getScopes())
			.state(authorizationCodeRequestAuthentication.getState())
			.additionalParameters(authorizationCodeRequestAuthentication.getAdditionalParameters())
			.build();
		authenticationContextBuilder.authorizationRequest(authorizationRequest);

		OAuth2AuthorizationConsent currentAuthorizationConsent = this.authorizationConsentService
			.findById(registeredClient.getId(), principal.getName());
		if (currentAuthorizationConsent != null) {
			authenticationContextBuilder.authorizationConsent(currentAuthorizationConsent);
		}

		if (this.authorizationConsentRequired.test(authenticationContextBuilder.build())) {
			if (promptValues.contains(OidcPrompt.NONE)) {
				// Return an error instead of displaying the consent page
				throw createException("consent_required", "prompt", authorizationCodeRequestAuthentication,
						registeredClient);
			}

			String state = DEFAULT_STATE_GENERATOR.generateKey();
			OAuth2Authorization authorization = authorizationBuilder(registeredClient, principal, authorizationRequest)
				.attribute(OAuth2ParameterNames.STATE, state)
				.build();

			if (this.logger.isTraceEnabled()) {
				this.logger.trace("Generated authorization consent state");
			}

			this.authorizationService.save(authorization);

			if (this.logger.isTraceEnabled()) {
				this.logger.trace("Saved authorization");
			}

View on GitHub (pinned to 96852e8860)

Solutions

  1. Remove prompt=none from the authorization request (or handle the consent_required error by falling back to an interactive flow with prompt=consent or no prompt) so the user can grant consent.
  2. Pre-authorize the client for the requested scopes so consent is no longer required (e.g. seed an authorized scope record or store OAuth2Authorization with approved scopes).
  3. Reduce requested scopes to only those the user has already consented to.
  4. If using a custom authorizationConsentRequired predicate, adjust it so consent is not required for already-authorized clients/scopes.

Example fix

// before
String redirect = "/oauth2/authorize?response_type=code&client_id=my-client&scope=read&prompt=none";
// after (fall back to interactive consent when consent is required)
String redirect = "/oauth2/authorize?response_type=code&client_id=my-client&scope=read"; // drop prompt=none, or catch consent_required and retry with prompt=consent
Defensive patterns

Strategy: try-catch

Validate before calling

// before sending the request, ensure prompt=none is only used when consent is already granted
boolean hasPromptNone = request.getPromptValues().contains("none");
boolean consentRequired = requestedScopes.stream().anyMatch(s -> !previouslyAuthorizedScopes.contains(s));
if (hasPromptNone && consentRequired) {
    // drop prompt=none or pre-authorize scopes; otherwise consent_required is guaranteed
    request = request.withPrompt(PromptValue.CONSENT);
}

Try / catch

try {
    authenticate(authorizationRequest);
} catch (OAuth2AuthorizationCodeRequestAuthenticationException e) {
    if ("consent_required".equals(e.getError().getErrorCode())) {
        // retry interactively without prompt=none
        redirectToConsentPage(stripPromptNone(originalRequest));
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: An OAuth2 authorization code request (OAuth2AuthorizationCodeRequestAuthenticationToken) includes prompt=none among its prompt values, the client is not already authorized for the requested scopes, and the authorizationConsentRequired predicate evaluates to true in OAuth2AuthorizationCodeRequestAuthenticationProvider.authenticate.

Common situations: Single-page or mobile apps doing silent re-authentication/token renewal with prompt=none after the user's consent expired or was revoked; a client adding new scopes that were never consented to; misconfigured RegisteredClient lacking pre-authorized scopes so consent is always required; switching identity providers or clearing authorization records in testing.

Related errors


AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10). Data as JSON: /api/errors/ce7d64c1c4d33148. Report an issue: GitHub.