spring-projects/spring-security · error · OAuth2AuthenticationException

invalid_token

invalid_token

Error message

OpenID Connect 1.0 Logout Request Parameter: id_token_hint

What it means

When processing an RP-initiated logout (OIDC Logout), OidcLogoutAuthenticationProvider looks up an OAuth2Authorization by the submitted id_token_hint using the ID token token type. If no authorization is found for that ID token, it throws invalid_token for id_token_hint — the logout request references a token the server does not recognize.

Source

Thrown at oauth2/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/oidc/authentication/OidcLogoutAuthenticationProvider.java:103

	 */
	public OidcLogoutAuthenticationProvider(RegisteredClientRepository registeredClientRepository,
			OAuth2AuthorizationService authorizationService, SessionRegistry sessionRegistry) {
		Assert.notNull(registeredClientRepository, "registeredClientRepository cannot be null");
		Assert.notNull(authorizationService, "authorizationService cannot be null");
		Assert.notNull(sessionRegistry, "sessionRegistry cannot be null");
		this.registeredClientRepository = registeredClientRepository;
		this.authorizationService = authorizationService;
		this.sessionRegistry = sessionRegistry;
	}

	@Override
	public Authentication authenticate(Authentication authentication) throws AuthenticationException {
		OidcLogoutAuthenticationToken oidcLogoutAuthentication = (OidcLogoutAuthenticationToken) authentication;

		OAuth2Authorization authorization = this.authorizationService
			.findByToken(oidcLogoutAuthentication.getIdTokenHint(), ID_TOKEN_TOKEN_TYPE);
		if (authorization == null) {
			throw createException(OAuth2ErrorCodes.INVALID_TOKEN, "id_token_hint");
		}

		if (this.logger.isTraceEnabled()) {
			this.logger.trace("Retrieved authorization with ID Token");
		}

		OAuth2Authorization.Token<OidcIdToken> authorizedIdToken = authorization.getToken(OidcIdToken.class);
		Assert.notNull(authorizedIdToken, "authorizedIdToken cannot be null");
		if (authorizedIdToken.isInvalidated() || authorizedIdToken.isBeforeUse()) {
			// Expired ID Token should be accepted
			throw createException(OAuth2ErrorCodes.INVALID_TOKEN, "id_token_hint");
		}

		RegisteredClient registeredClient = this.registeredClientRepository
			.findById(authorization.getRegisteredClientId());
		Assert.notNull(registeredClient, "registeredClient cannot be null");

		if (this.logger.isTraceEnabled()) {

View on GitHub (pinned to 96852e8860)

Solutions

  1. Issue the logout from a client session whose ID token was issued by the same running authorization server
  2. Use a shared, persistent OAuth2AuthorizationService (e.g. JDBC/Redis) across all server instances
  3. Verify the id_token_hint value is the raw ID token JWT issued by this server, not a different token type

Example fix

// before
authorizationService = new InMemoryOAuth2AuthorizationService(); // lost on restart
// after
authorizationService = new JdbcOAuth2AuthorizationService(jdbcOperations, registeredClientRepository);
Defensive patterns

Strategy: try-catch

Validate before calling

// Decode the id_token_hint JWT and confirm iss matches this authorization server before initiating logout

Try / catch

try {
    authenticationManager.authenticate(new OidcLogoutAuthenticationToken(...));
} catch (AuthenticationException ex) {
    // invalid_token for id_token_hint: re-authenticate the user and obtain a fresh ID token
}

Prevention

When it happens

Trigger: Submitting a logout request to the OIDC logout endpoint with an id_token_hint that was not issued by this authorization server, was issued by a different server instance/authorizationService store, or whose session/authorization record was deleted.

Common situations: Multi-instance deployments where the in-memory authorization service is not shared (token issued by another node); restarting the server with an in-memory OAuth2AuthorizationService so previously issued ID tokens are unknown; sending an id_token_hint from a different environment (staging token to prod).

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


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