spring-projects/spring-security · error · OAuth2AuthenticationException

authorization_request_not_found

authorization_request_not_found

Error message

authorization_request_not_found

What it means

During the OAuth2 callback the filter removes the stored OAuth2AuthorizationRequest (typically from the session via HttpSessionOAuth2AuthorizationRequestRepository). If no stored request exists, the callback is unsolicited and this error with code authorization_request_not_found is thrown.

Source

Thrown at oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/OAuth2LoginAuthenticationFilter.java:178

		Assert.notNull(clientRegistrationRepository, "clientRegistrationRepository cannot be null");
		Assert.notNull(authorizedClientRepository, "authorizedClientRepository cannot be null");
		this.clientRegistrationRepository = clientRegistrationRepository;
		this.authorizedClientRepository = authorizedClientRepository;
	}

	@Override
	public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
			throws AuthenticationException {
		MultiValueMap<String, String> params = OAuth2AuthorizationResponseUtils.toMultiMap(request.getParameterMap());
		if (!OAuth2AuthorizationResponseUtils.isAuthorizationResponse(params)) {
			OAuth2Error oauth2Error = new OAuth2Error(OAuth2ErrorCodes.INVALID_REQUEST);
			throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
		}
		OAuth2AuthorizationRequest authorizationRequest = this.authorizationRequestRepository
			.removeAuthorizationRequest(request, response);
		if (authorizationRequest == null) {
			OAuth2Error oauth2Error = new OAuth2Error(AUTHORIZATION_REQUEST_NOT_FOUND_ERROR_CODE);
			throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
		}
		String registrationId = authorizationRequest.getAttribute(OAuth2ParameterNames.REGISTRATION_ID);
		Assert.hasText(registrationId, "registrationId cannot be empty");
		ClientRegistration clientRegistration = this.clientRegistrationRepository.findByRegistrationId(registrationId);
		if (clientRegistration == null) {
			OAuth2Error oauth2Error = new OAuth2Error(CLIENT_REGISTRATION_NOT_FOUND_ERROR_CODE,
					"Client Registration not found with Id: " + registrationId, null);
			throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
		}
		// @formatter:off
		String redirectUri = UriComponentsBuilder.fromUriString(UrlUtils.buildFullRequestUrl(request))
				.replaceQuery(null)
				.build()
				.toUriString();
		// @formatter:on
		OAuth2AuthorizationResponse authorizationResponse = OAuth2AuthorizationResponseUtils.convert(params,
				redirectUri);
		Object authenticationDetails = this.authenticationDetailsSource.buildDetails(request);

View on GitHub (pinned to 96852e8860)

Solutions

  1. Use sticky sessions or a shared session store (e.g. Spring Session with Redis/JDBC) across all nodes
  2. Verify the JSESSIONID cookie survives the redirect to the IdP (check SameSite=None; Secure when IdP is cross-site)
  3. Have users restart the login flow from /oauth2/authorization/{registrationId}; clear stale cookies
  4. If callbacks are intentionally unsolicited, configure the authorizationRequestRepository appropriately or relax the filter per Spring Security docs on unsolicited responses

Example fix

// before
// multiple nodes, in-memory sessions, round-robin LB
// after
// enable Spring Session
<dependency>
  <groupId>org.springframework.session</groupId>
  <artifactId>spring-session-data-redis</artifactId>
</dependency>
Defensive patterns

Strategy: try-catch

Try / catch

catch (OAuth2AuthenticationException e) {
    if ("authorization_request_not_found".equals(e.getError().getErrorCode())) {
        // redirect user to /oauth2/authorization/{id} to restart login
    }
}

Prevention

When it happens

Trigger: The redirect_uri is hit with code/state parameters but the session that started login is gone: cookie lost, session expired, server restarted without sticky sessions, or the callback arrives in a different browser/session.

Common situations: Multiple backend nodes without sticky sessions or shared session store; SameSite/cookie policies dropping JSESSIONID on cross-site redirect; users clicking an old callback link from history; cookies blocked by the browser.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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