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
- Register the client: add a RegisteredClient with that client_id to the RegisteredClientRepository bean (InMemoryRegisteredClientRepository or JdbcRegisteredClientRepository).
- Check for typos/case sensitivity in the client_id sent by the client application.
- If DB-backed, query the client table directly: SELECT * FROM registered_client WHERE client_id = '...'; and fix missing/mis-inserted rows.
- 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
- Keep client registrations in source-controlled config or a managed DB seeded consistently per environment.
- Add an integration test asserting each configured client_id resolves in the RegisteredClientRepository.
- Validate client_id spelling against the repository at deploy time.
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.
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10).
Data as JSON: /api/errors/086d43fc17fc2144.
Report an issue: GitHub.