spring-projects/spring-security · error · OAuth2AuthenticationException

invalid_client

invalid_client

Error message

Client authentication failed: client_id

What it means

ClientSecretAuthenticationProvider.authenticate looks up the RegisteredClient via RegisteredClientRepository.findByClientId(clientId). If no client with that client_id is registered, it throws an OAuth2AuthorizationCodeGrant-style invalid_client OAuth2AuthenticationException with detail 'client_id'. This guards the token/authorization endpoints against unknown OAuth2 clients.

Source

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

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

	@Override
	public @Nullable Authentication authenticate(Authentication authentication) throws AuthenticationException {
		OAuth2ClientAuthenticationToken clientAuthentication = (OAuth2ClientAuthenticationToken) authentication;

		// @formatter:off
		if (!ClientAuthenticationMethod.CLIENT_SECRET_BASIC.equals(clientAuthentication.getClientAuthenticationMethod()) &&
				!ClientAuthenticationMethod.CLIENT_SECRET_POST.equals(clientAuthentication.getClientAuthenticationMethod())) {
			return null;
		}
		// @formatter:on

		String clientId = clientAuthentication.getPrincipal().toString();
		RegisteredClient registeredClient = this.registeredClientRepository.findByClientId(clientId);
		if (registeredClient == null) {
			throw invalidClientException(OAuth2ParameterNames.CLIENT_ID);
		}

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

		if (!registeredClient.getClientAuthenticationMethods()
			.contains(clientAuthentication.getClientAuthenticationMethod())) {
			throw invalidClientException("authentication_method");
		}

		Object credentials = clientAuthentication.getCredentials();
		if (credentials == null) {
			throw invalidClientException("credentials");
		}

		String clientSecret = credentials.toString();
		if (!this.passwordEncoder.matches(clientSecret, registeredClient.getClientSecret())) {

View on GitHub (pinned to 96852e8860)

Solutions

  1. Register the client: add a RegisteredClient with that client_id to the RegisteredClientRepository bean (InMemoryRegisteredClientRepository or JdbcRegisteredClientRepository).
  2. Check for typos/case sensitivity in the client_id sent by the client application.
  3. If DB-backed, query the client table directly: SELECT * FROM registered_client WHERE client_id = '...'; and fix missing/mis-inserted rows.
  4. Confirm the OAuth2ClientAuthenticationProvider configured with your RegisteredClientRepository is registered on the security filter chain so the correct repository is consulted.

Example fix

// before
@Bean
RegisteredClientRepository registeredClientRepository() {
    return new InMemoryRegisteredClientRepository(clientA); // only clientA registered
}
// after
@Bean
RegisteredClientRepository registeredClientRepository() {
    return new InMemoryRegisteredClientRepository(clientA, clientB); // clientB added
}
Defensive patterns

Strategy: validation

Validate before calling

// before calling the token endpoint, ensure the client exists in the repository
boolean registered = registeredClientRepository.findByClientId(clientId) != null;
if (!registered) throw new IllegalStateException("client_id not registered: " + clientId);

Try / catch

try {
    // client-side token call
} catch (HttpClientErrorException.Unauthorized e) {
    if (e.getResponseBodyAsString().contains("invalid_client")) {
        // verify client_id registration before retrying
    }
}

Prevention

When it happens

Trigger: Any client authentication request (OAuth2ClientAuthenticationToken) processed by ClientSecretAuthenticationProvider whose client_id is not found in the configured RegisteredClientRepository — e.g. POST /oauth2/token with an unregistered client_id, or authorization endpoint requests requiring client authentication.

Common situations: Client never registered via a RegisteredClientRepository bean; typo in client_id; using the wrong repository (in-memory config while clients are DB-backed); environment mismatch (client registered only in dev); JdbcRegisteredClientRepository row missing after migration.

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/086d43fc17fc2144. Report an issue: GitHub.