{"record":{"id":"086d43fc17fc2144","repo":"spring-projects/spring-security","slug":"invalid-client-086d43","errorCode":"invalid_client","errorMessage":"Client authentication failed: client_id","messagePattern":"Client authentication failed: client_id","errorType":"error_code","errorClass":"OAuth2AuthenticationException","httpStatus":null,"severity":"error","filePath":"oauth2/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/ClientSecretAuthenticationProvider.java","lineNumber":109,"sourceCode":"\t\tAssert.notNull(passwordEncoder, \"passwordEncoder cannot be null\");\n\t\tthis.passwordEncoder = passwordEncoder;\n\t}\n\n\t@Override\n\tpublic @Nullable Authentication authenticate(Authentication authentication) throws AuthenticationException {\n\t\tOAuth2ClientAuthenticationToken clientAuthentication = (OAuth2ClientAuthenticationToken) authentication;\n\n\t\t// @formatter:off\n\t\tif (!ClientAuthenticationMethod.CLIENT_SECRET_BASIC.equals(clientAuthentication.getClientAuthenticationMethod()) &&\n\t\t\t\t!ClientAuthenticationMethod.CLIENT_SECRET_POST.equals(clientAuthentication.getClientAuthenticationMethod())) {\n\t\t\treturn null;\n\t\t}\n\t\t// @formatter:on\n\n\t\tString clientId = clientAuthentication.getPrincipal().toString();\n\t\tRegisteredClient registeredClient = this.registeredClientRepository.findByClientId(clientId);\n\t\tif (registeredClient == null) {\n\t\t\tthrow invalidClientException(OAuth2ParameterNames.CLIENT_ID);\n\t\t}\n\n\t\tif (this.logger.isTraceEnabled()) {\n\t\t\tthis.logger.trace(\"Retrieved registered client\");\n\t\t}\n\n\t\tif (!registeredClient.getClientAuthenticationMethods()\n\t\t\t.contains(clientAuthentication.getClientAuthenticationMethod())) {\n\t\t\tthrow invalidClientException(\"authentication_method\");\n\t\t}\n\n\t\tObject credentials = clientAuthentication.getCredentials();\n\t\tif (credentials == null) {\n\t\t\tthrow invalidClientException(\"credentials\");\n\t\t}\n\n\t\tString clientSecret = credentials.toString();\n\t\tif (!this.passwordEncoder.matches(clientSecret, registeredClient.getClientSecret())) {","sourceCodeStart":91,"sourceCodeEnd":127,"githubUrl":"https://github.com/spring-projects/spring-security/blob/96852e8860138a482cb13d1479573f24ff6443c6/oauth2/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/ClientSecretAuthenticationProvider.java#L91-L127","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\n@Bean\nRegisteredClientRepository registeredClientRepository() {\n    return new InMemoryRegisteredClientRepository(clientA); // only clientA registered\n}\n// after\n@Bean\nRegisteredClientRepository registeredClientRepository() {\n    return new InMemoryRegisteredClientRepository(clientA, clientB); // clientB added\n}","handlingStrategy":"validation","validationCode":"// before calling the token endpoint, ensure the client exists in the repository\nboolean registered = registeredClientRepository.findByClientId(clientId) != null;\nif (!registered) throw new IllegalStateException(\"client_id not registered: \" + clientId);","typeGuard":null,"tryCatchPattern":"try {\n    // client-side token call\n} catch (HttpClientErrorException.Unauthorized e) {\n    if (e.getResponseBodyAsString().contains(\"invalid_client\")) {\n        // verify client_id registration before retrying\n    }\n}","preventionTips":["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."],"tags":["oauth2","client-authentication","invalid-client","spring-authorization-server"],"backgroundTag":"resource-not-found","analyzedSha":"96852e8860138a482cb13d1479573f24ff6443c6","analyzedAt":"2026-09-10T23:25:23.477Z","contentChangedAt":"2026-09-10T23:25:23.477Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}