spring-projects/spring-security · error · OAuth2AuthenticationException

invalid_request

invalid_request

Error message

OpenID Connect 1.0 Logout Request Parameter: client_id

What it means

When the logout request includes an explicit client_id parameter, OidcLogoutAuthenticationProvider requires it to match the clientId of the registered client that owns the ID token's authorization. A mismatch throws invalid_request naming client_id — the request parameters are internally inconsistent.

Source

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

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

		if (this.logger.isTraceEnabled()) {
			this.logger.trace("Retrieved registered client");
		}

		OidcIdToken idToken = authorizedIdToken.getToken();

		// Validate client identity
		List<String> audClaim = idToken.getAudience();
		if (CollectionUtils.isEmpty(audClaim) || !audClaim.contains(registeredClient.getClientId())) {
			throw createException(OAuth2ErrorCodes.INVALID_TOKEN, IdTokenClaimNames.AUD);
		}
		if (StringUtils.hasText(oidcLogoutAuthentication.getClientId())
				&& !oidcLogoutAuthentication.getClientId().equals(registeredClient.getClientId())) {
			throw createException(OAuth2ErrorCodes.INVALID_REQUEST, OAuth2ParameterNames.CLIENT_ID);
		}

		OidcLogoutAuthenticationContext context = OidcLogoutAuthenticationContext.with(oidcLogoutAuthentication)
			.registeredClient(registeredClient)
			.build();
		this.authenticationValidator.accept(context);

		if (this.logger.isTraceEnabled()) {
			this.logger.trace("Validated logout request parameters");
		}

		// Validate user identity
		if (oidcLogoutAuthentication.isPrincipalAuthenticated()) {
			Authentication currentUserPrincipal = (Authentication) oidcLogoutAuthentication.getPrincipal();
			Authentication authorizedUserPrincipal = authorization.getAttribute(Principal.class.getName());
			Assert.notNull(authorizedUserPrincipal, "authorizedUserPrincipal cannot be null");
			if (!StringUtils.hasText(idToken.getSubject())
					|| !currentUserPrincipal.getName().equals(authorizedUserPrincipal.getName())) {

View on GitHub (pinned to 96852e8860)

Solutions

  1. Make the client_id in the logout request match the client the id_token_hint was issued to
  2. Dynamically render client_id from the current client's registration instead of hardcoding it
  3. Omit client_id if the application cannot guarantee the correct value (the token alone identifies the client)

Example fix

// before
<a href="/oauth2/logout?id_token_hint=${idToken}&client_id=old-client-id">Log out</a>
// after
<a href="/oauth2/logout?id_token_hint=${idToken}&client_id=${clientId}">Log out</a>
Defensive patterns

Strategy: validation

Validate before calling

if (clientId != null && !clientId.equals(clientIdOfIdTokenHint)) {
    throw new IllegalArgumentException("client_id does not match id_token_hint issuer client");
}

Prevention

When it happens

Trigger: Posting to the OIDC logout endpoint with id_token_hint from client A but client_id parameter set to client B (any non-empty client_id that differs from the token's registered client).

Common situations: Hardcoded client_id in the logout template not matching the currently logged-in client; multi-client apps sending the wrong app's client_id; copy-paste of logout URLs between environments where client ids differ.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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