{"record":{"id":"7f5d43e287b04297","repo":"spring-projects/spring-security","slug":"invalid-client","errorCode":"INVALID_CLIENT","errorMessage":"Failed to find a Signature Verifier for Client: '<registeredClient.getId()>'. Check to ensure you have configured the JWK Set URL.","messagePattern":"Failed to find a Signature Verifier for Client: '<registeredClient\\.getId\\(\\)>'\\. Check to ensure you have configured the JWK Set URL\\.","errorType":"error_code","errorClass":"OAuth2AuthenticationException","httpStatus":null,"severity":"error","filePath":"oauth2/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/JwtClientAssertionDecoderFactory.java","lineNumber":144,"sourceCode":"\t * @param jwtValidatorFactory the factory that provides an\n\t * {@link OAuth2TokenValidator} for the specified {@link RegisteredClient}\n\t */\n\tpublic void setJwtValidatorFactory(Function<RegisteredClient, OAuth2TokenValidator<Jwt>> jwtValidatorFactory) {\n\t\tAssert.notNull(jwtValidatorFactory, \"jwtValidatorFactory cannot be null\");\n\t\tthis.jwtValidatorFactory = jwtValidatorFactory;\n\t}\n\n\tprivate static NimbusJwtDecoder buildDecoder(RegisteredClient registeredClient) {\n\t\tJwsAlgorithm jwsAlgorithm = registeredClient.getClientSettings()\n\t\t\t.getTokenEndpointAuthenticationSigningAlgorithm();\n\t\tif (jwsAlgorithm instanceof SignatureAlgorithm) {\n\t\t\tString jwkSetUrl = registeredClient.getClientSettings().getJwkSetUrl();\n\t\t\tif (!StringUtils.hasText(jwkSetUrl)) {\n\t\t\t\tOAuth2Error oauth2Error = new OAuth2Error(OAuth2ErrorCodes.INVALID_CLIENT,\n\t\t\t\t\t\t\"Failed to find a Signature Verifier for Client: '\" + registeredClient.getId()\n\t\t\t\t\t\t\t\t+ \"'. Check to ensure you have configured the JWK Set URL.\",\n\t\t\t\t\t\tJWT_CLIENT_AUTHENTICATION_ERROR_URI);\n\t\t\t\tthrow new OAuth2AuthenticationException(oauth2Error);\n\t\t\t}\n\t\t\treturn NimbusJwtDecoder.withJwkSetUri(jwkSetUrl)\n\t\t\t\t.jwsAlgorithm((SignatureAlgorithm) jwsAlgorithm)\n\t\t\t\t.restOperations(restTemplate)\n\t\t\t\t.build();\n\t\t}\n\t\tif (jwsAlgorithm instanceof MacAlgorithm) {\n\t\t\tString clientSecret = registeredClient.getClientSecret();\n\t\t\tif (!StringUtils.hasText(clientSecret)) {\n\t\t\t\tOAuth2Error oauth2Error = new OAuth2Error(OAuth2ErrorCodes.INVALID_CLIENT,\n\t\t\t\t\t\t\"Failed to find a Signature Verifier for Client: '\" + registeredClient.getId()\n\t\t\t\t\t\t\t\t+ \"'. Check to ensure you have configured the client secret.\",\n\t\t\t\t\t\tJWT_CLIENT_AUTHENTICATION_ERROR_URI);\n\t\t\t\tthrow new OAuth2AuthenticationException(oauth2Error);\n\t\t\t}\n\t\t\tSecretKeySpec secretKeySpec = new SecretKeySpec(clientSecret.getBytes(StandardCharsets.UTF_8),\n\t\t\t\t\tJCA_ALGORITHM_MAPPINGS.get(jwsAlgorithm));\n\t\t\treturn NimbusJwtDecoder.withSecretKey(secretKeySpec).macAlgorithm((MacAlgorithm) jwsAlgorithm).build();","sourceCodeStart":126,"sourceCodeEnd":162,"githubUrl":"https://github.com/spring-projects/spring-security/blob/96852e8860138a482cb13d1479573f24ff6443c6/oauth2/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/JwtClientAssertionDecoderFactory.java#L126-L162","documentation":"In the OAuth2 Authorization Server, when a client authenticates with a JWT client assertion signed with an asymmetric algorithm (e.g. RS256), the server builds a JwtDecoder that fetches the client's public keys via a JWK Set URL. JwtClientAssertionDecoderFactory.buildDecoder throws this INVALID_CLIENT error when the client's JwkSetUrl client setting is missing or blank, so no signature verifier can be constructed.","triggerScenarios":"A client sends a private_key_jwt client assertion, but RegisteredClient.getClientSettings().getJwkSetUrl() was never set (or is empty string/whitespace) on the server for that client, so buildDecoder fails before decoding the assertion.","commonSituations":"Registering a client for client_secret_jwt/private_key_jwt auth without the jwk-set-url client setting; loading clients from a database where the JWK Set URL column is null; copying a client registration from a symmetric-secret example; typos in settings builder calls.","solutions":["Set the JWK Set URL on the client: RegisteredClient.withClient(id).clientSettings(ClientSettings.builder().jwkSetUrl(\"https://client.example.com/jwks\").build()).build()","Verify the stored client record actually contains a non-empty jwkSetUrl (check DB/claim source if clients are loaded dynamically).","Alternatively configure the client's JWK Set URI through your RegisteredClientRepository registration code path used at authorization time.","Confirm the client is actually using private_key_jwt and that the intended auth method matches its registration (token_endpoint_authentication_method)."],"exampleFix":"// before\nRegisteredClient client = RegisteredClient.withId(UUID.randomUUID().toString())\n    .clientId(\"client-a\")\n    .clientAuthenticationMethod(ClientAuthenticationMethod.PRIVATE_KEY_JWT)\n    .build();\n\n// after\nRegisteredClient client = RegisteredClient.withId(UUID.randomUUID().toString())\n    .clientId(\"client-a\")\n    .clientAuthenticationMethod(ClientAuthenticationMethod.PRIVATE_KEY_JWT)\n    .clientSettings(ClientSettings.builder()\n        .jwkSetUrl(\"https://client-a.example.com/jwks\")\n        .build())\n    .build();","handlingStrategy":"validation","validationCode":"if (client.getClientSettings() == null ||\n    !StringUtils.hasText(client.getClientSettings().getJwkSetUrl())) {\n    throw new IllegalStateException(\n        \"Client \" + client.getId() + \" uses private_key_jwt but has no jwkSetUrl configured\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    // token request with private_key_jwt\n} catch (OAuth2AuthenticationException ex) {\n    if (OAuth2ErrorCodes.INVALID_CLIENT.equals(ex.getError().getErrorCode())) {\n        log.error(\"Client assertion rejected: {}. Verify jwkSetUrl registration.\",\n            ex.getError().getDescription());\n    }\n    throw ex;\n}","preventionTips":["Always pair ClientAuthenticationMethod.PRIVATE_KEY_JWT with ClientSettings.jwkSetUrl in your client registration factory","Add a startup test that requests tokens for every registered client","If clients come from a database, validate jwkSetUrl non-null on load"],"tags":["oauth2","jwt","client-authentication","config"],"backgroundTag":"missing-required-config-field","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"}