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

  1. Register the client with the exact client_id and ClientAuthenticationMethod.TLS_CLIENT_AUTH in the RegisteredClientRepository.
  2. Verify the certificate's client identity maps to the registered client_id (check the proxy/extractor that builds the authentication principal).
  3. Confirm both sides use the same environment's client registry.
  4. 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

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

Related errors


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