spring-projects/spring-security · error · OAuth2AuthenticationException
invalid_client
invalid_client
Error message
Client authentication failed: client_id
What it means
X509ClientCertificateAuthenticationProvider.authenticate handles mTLS client authentication (RFC 8705) with the tls_client_auth method. It resolves the client_id from the client authentication token; if RegisteredClientRepository.findClientId returns no client, it throws invalid_client with message 'Client authentication failed: client_id'.
Source
Thrown at oauth2/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/X509ClientCertificateAuthenticationProvider.java:95
Assert.notNull(authorizationService, "authorizationService cannot be null");
this.registeredClientRepository = registeredClientRepository;
this.codeVerifierAuthenticator = new CodeVerifierAuthenticator(authorizationService);
}
@Override
public @Nullable Authentication authenticate(Authentication authentication) throws AuthenticationException {
OAuth2ClientAuthenticationToken clientAuthentication = (OAuth2ClientAuthenticationToken) authentication;
if (!ClientAuthenticationMethod.TLS_CLIENT_AUTH.equals(clientAuthentication.getClientAuthenticationMethod())
&& !ClientAuthenticationMethod.SELF_SIGNED_TLS_CLIENT_AUTH
.equals(clientAuthentication.getClientAuthenticationMethod())) {
return null;
}
String clientId = clientAuthentication.getPrincipal().toString();
RegisteredClient registeredClient = this.registeredClientRepository.findByClientId(clientId);
if (registeredClient == null) {
throw invalidClient(OAuth2ParameterNames.CLIENT_ID);
}
if (this.logger.isTraceEnabled()) {
this.logger.trace("Retrieved registered client");
}
if (!registeredClient.getClientAuthenticationMethods()
.contains(clientAuthentication.getClientAuthenticationMethod())) {
throw invalidClient("authentication_method");
}
if (!(clientAuthentication.getCredentials() instanceof X509Certificate[])) {
throw invalidClient("credentials");
}
OAuth2ClientAuthenticationContext authenticationContext = OAuth2ClientAuthenticationContext
.with(clientAuthentication)
.registeredClient(registeredClient)View on GitHub (pinned to 96852e8860)
Solutions
- Register the client with the exact client_id and ClientAuthenticationMethod.TLS_CLIENT_AUTH in the RegisteredClientRepository.
- Verify the certificate's client identity maps to the registered client_id (check the proxy/extractor that builds the authentication principal).
- Confirm both sides use the same environment's client registry.
- Enable trace logging to see the received client_id value.
Example fix
// before: client unregistered
// after: register tls_client_auth client
RegisteredClient.create().clientId("mtls-client")
.clientAuthenticationMethod(ClientAuthenticationMethod.TLS_CLIENT_AUTH)
.clientSettings(ClientSettings.builder()
.x509CertificateSubjectDN("CN=mtls-client,OU=Acme,O=Acme,C=US")
.build())
.build(); Defensive patterns
Strategy: validation
Validate before calling
RegisteredClient rc = registeredClientRepository.findByClientId(clientId);
if (rc == null) { throw new IllegalStateException("mtls client not registered: " + clientId); } Try / catch
catch (OAuth2AuthenticationException e) { if ("invalid_client".equals(e.getError().getErrorCode())) { registerTlsClientAuthClient(); } } Prevention
- Register tls_client_auth clients with TLS_CLIENT_AUTH method and subject DN
- Verify certificate-to-client_id mapping in the proxy
- Sync registrations across environments
When it happens
Trigger: An mTLS token request presenting a client certificate whose client_id (from the authentication principal) has no matching RegisteredClient in the repository.
Common situations: tls_client_auth client not registered on the server; certificate issued for a client id that was renamed or removed; requests routed to an environment lacking the client registration; misconfigured reverse proxy not passing the certificate-derived client id.
Understand the failure class
- 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/3b91f2f693ea92ae.
Report an issue: GitHub.