{"record":{"id":"7edbb3563a9d8362","repo":"spring-projects/spring-security","slug":"missing-signature-verifier-7edbb3","errorCode":"missing_signature_verifier","errorMessage":"Failed to find a Signature Verifier for Client Registration: '{registrationId}'. Check to ensure you have configured the JwkSet URI.","messagePattern":"Failed to find a Signature Verifier for Client Registration: '(.+?)'\\. Check to ensure you have configured the JwkSet URI\\.","errorType":"error_code","errorClass":"OAuth2AuthenticationException","httpStatus":null,"severity":"error","filePath":"config/src/main/java/org/springframework/security/config/web/server/OidcBackChannelLogoutReactiveAuthenticationManager.java","lineNumber":84,"sourceCode":"\tprivate ReactiveJwtDecoderFactory<ClientRegistration> logoutTokenDecoderFactory;\n\n\t/**\n\t * Construct an {@link OidcBackChannelLogoutReactiveAuthenticationManager}.\n\t */\n\tOidcBackChannelLogoutReactiveAuthenticationManager() {\n\t\tJwtTypeValidator type = new JwtTypeValidator(\"JWT\", \"logout+jwt\");\n\t\ttype.setAllowEmpty(true);\n\t\tFunction<ClientRegistration, OAuth2TokenValidator<Jwt>> jwtValidator = (clientRegistration) -> JwtValidators\n\t\t\t.createDefaultWithValidators(type, new OidcBackChannelLogoutTokenValidator(clientRegistration));\n\t\tthis.logoutTokenDecoderFactory = (clientRegistration) -> {\n\t\t\tString jwkSetUri = clientRegistration.getProviderDetails().getJwkSetUri();\n\t\t\tif (!StringUtils.hasText(jwkSetUri)) {\n\t\t\t\tOAuth2Error oauth2Error = new OAuth2Error(\"missing_signature_verifier\",\n\t\t\t\t\t\t\"Failed to find a Signature Verifier for Client Registration: '\"\n\t\t\t\t\t\t\t\t+ clientRegistration.getRegistrationId()\n\t\t\t\t\t\t\t\t+ \"'. Check to ensure you have configured the JwkSet URI.\",\n\t\t\t\t\t\tnull);\n\t\t\t\tthrow new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());\n\t\t\t}\n\t\t\tNimbusReactiveJwtDecoder decoder = NimbusReactiveJwtDecoder.withJwkSetUri(jwkSetUri).build();\n\t\t\tdecoder.setJwtValidator(jwtValidator.apply(clientRegistration));\n\t\t\tdecoder.setClaimSetConverter(\n\t\t\t\t\tnew ClaimTypeConverter(OidcIdTokenDecoderFactory.createDefaultClaimTypeConverters()));\n\t\t\treturn decoder;\n\t\t};\n\t}\n\n\t/**\n\t * {@inheritDoc}\n\t */\n\t@Override\n\tpublic Mono<Authentication> authenticate(Authentication authentication) throws AuthenticationException {\n\t\tif (!(authentication instanceof OidcLogoutAuthenticationToken token)) {\n\t\t\treturn Mono.empty();\n\t\t}\n\t\tString logoutToken = token.getLogoutToken();","sourceCodeStart":66,"sourceCodeEnd":102,"githubUrl":"https://github.com/spring-projects/spring-security/blob/96852e8860138a482cb13d1479573f24ff6443c6/config/src/main/java/org/springframework/security/config/web/server/OidcBackChannelLogoutReactiveAuthenticationManager.java#L66-L102","documentation":"OidcBackChannelLogoutReactiveAuthenticationManager builds a NimbusReactiveJwtDecoder per client registration to verify back-channel logout tokens. It requires a JWK Set URI on the client registration; if jwkSetUri is blank it throws an OAuth2AuthenticationException with code 'missing_signature_verifier'.","triggerScenarios":"Enabling OIDC back-channel logout support (oidcLogout in reactive ServerHttpSecurity) while the ClientRegistration used has no jwkSetUri configured (e.g. only an issuer or client authentication method set, or a private-key jwt client).","commonSituations":"Configuring a reactive OAuth2 login client whose provider metadata does not yield a jwks_uri; hand-built ClientRegistration missing jwkSetUri; registering a custom client registration bean without the JWK Set endpoint.","solutions":["Set the jwkSetUri on the ClientRegistration (ClientRegistration.withRegistrationId(...).jwkSetUri(\"https://idp/.well-known/jwks.json\"))","Ensure issuer-uri based registration resolves provider metadata containing jwks_uri","If the provider has no JWK Set endpoint, back-channel logout token verification cannot work; use a provider that signs and exposes JWKS"],"exampleFix":"// before\nClientRegistration.withRegistrationId(\"my-idp\")\n    .issuerUri(\"https://idp.example.com\")\n    .build();\n\n// after\nClientRegistration.withRegistrationId(\"my-idp\")\n    .issuerUri(\"https://idp.example.com\")\n    .jwkSetUri(\"https://idp.example.com/.well-known/jwks.json\")\n    .build();","handlingStrategy":"validation","validationCode":"if (!StringUtils.hasText(clientRegistration.getProviderDetails().getJwkSetUri())) {\n  throw new IllegalStateException(\"ClientRegistration '\" + clientRegistration.getRegistrationId()\n      + \"' needs a jwkSetUri for back-channel logout\");\n}","typeGuard":null,"tryCatchPattern":"try {\n  authenticationManager.authenticate(logoutToken);\n} catch (OAuth2AuthenticationException e) {\n  if (\"missing_signature_verifier\".equals(e.getError().getErrorCode())) {\n    // reconfigure the ClientRegistration with a jwkSetUri\n  }\n}","preventionTips":["Verify every ClientRegistration has a jwkSetUri (directly or via issuer metadata) before enabling oidcLogout","Test IDP discovery output for jwks_uri presence","Fail fast at startup by iterating registrations and checking jwkSetUri"],"tags":["oauth2","oidc","jwt","jwks","reactive"],"backgroundTag":"missing-signature-verifier","analyzedSha":"96852e8860138a482cb13d1479573f24ff6443c6","analyzedAt":"2026-09-10T23:25:23.477Z","contentChangedAt":"2026-09-10T23:25:23.477Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}