{"record":{"id":"ff8d0cf8176ed095","repo":"spring-projects/spring-security","slug":"invalid-client-metadata","errorCode":"invalid_client_metadata","errorMessage":"Invalid Client Registration: jwks_uri","messagePattern":"Invalid Client Registration: jwks_uri","errorType":"error_code","errorClass":"OAuth2AuthenticationException","httpStatus":null,"severity":"error","filePath":"oauth2/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2ClientRegistrationAuthenticationValidator.java","lineNumber":208,"sourceCode":"\t\t\tcatch (URISyntaxException ex) {\n\t\t\t\tthrow createException(OAuth2ErrorCodes.INVALID_REDIRECT_URI,\n\t\t\t\t\t\tOAuth2ClientMetadataClaimNames.REDIRECT_URIS);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate static void validateJwkSetUri(OAuth2ClientRegistrationAuthenticationContext authenticationContext) {\n\t\tOAuth2ClientRegistrationAuthenticationToken clientRegistrationAuthentication = authenticationContext\n\t\t\t.getAuthentication();\n\t\tURL jwkSetUrl = clientRegistrationAuthentication.getClientRegistration().getJwkSetUrl();\n\t\tif (jwkSetUrl == null) {\n\t\t\treturn;\n\t\t}\n\t\tif (!\"https\".equalsIgnoreCase(jwkSetUrl.getProtocol())) {\n\t\t\tif (LOGGER.isDebugEnabled()) {\n\t\t\t\tLOGGER.debug(LogMessage.format(\"Invalid request: jwks_uri does not use https ('%s')\", jwkSetUrl));\n\t\t\t}\n\t\t\tthrow createException(\"invalid_client_metadata\", OAuth2ClientMetadataClaimNames.JWKS_URI);\n\t\t}\n\t}\n\n\tprivate static void validateJwkSetUriSimple(OAuth2ClientRegistrationAuthenticationContext authenticationContext) {\n\t\t// No validation. Preserves prior behavior.\n\t}\n\n\tprivate static void validateScope(OAuth2ClientRegistrationAuthenticationContext authenticationContext) {\n\t\tOAuth2ClientRegistrationAuthenticationToken clientRegistrationAuthentication = authenticationContext\n\t\t\t.getAuthentication();\n\t\tList<String> scopes = clientRegistrationAuthentication.getClientRegistration().getScopes();\n\t\tif (!CollectionUtils.isEmpty(scopes)) {\n\t\t\tif (LOGGER.isDebugEnabled()) {\n\t\t\t\tLOGGER.debug(LogMessage.format(\n\t\t\t\t\t\t\"Invalid request: scope must not be set during Dynamic Client Registration ('%s')\", scopes));\n\t\t\t}\n\t\t\tthrow createException(OAuth2ErrorCodes.INVALID_SCOPE, OAuth2ClientMetadataClaimNames.SCOPE);\n\t\t}","sourceCodeStart":190,"sourceCodeEnd":226,"githubUrl":"https://github.com/spring-projects/spring-security/blob/96852e8860138a482cb13d1479573f24ff6443c6/oauth2/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2ClientRegistrationAuthenticationValidator.java#L190-L226","documentation":"When dynamic client registration includes a jwks_uri, validateJwkSetUri requires it to use the https protocol; otherwise it throws invalid_client_metadata for the jwks_uri claim. This prevents clients from publishing signing keys over insecure transports where they could be tampered with.","triggerScenarios":"POSTing a client registration whose jwks_uri is 'http://...' (plain HTTP) or otherwise non-https, e.g. 'http://client.example.org/jwks.json'.","commonSituations":"Local development with http endpoints being registered against a production authorization server; self-hosted JWKS behind a TLS-terminating proxy exposed as http internally but registered as such; copying a localhost test URL into production registration.","solutions":["Serve the JWKS over https and register the https URL (e.g. https://client.example.org/jwks.json)","Put the JWKS behind a TLS-enabled reverse proxy or CDN","If testing locally, use a tunnel (e.g. ngrok) to get an https URL, or inline keys via jwks instead of jwks_uri if supported"],"exampleFix":"// before\n{\"jwks_uri\": \"http://client.example.org/jwks.json\"}\n// after\n{\"jwks_uri\": \"https://client.example.org/jwks.json\"}","handlingStrategy":"validation","validationCode":"if (jwksUri != null && !jwksUri.startsWith(\"https://\")) throw new IllegalArgumentException(\"jwks_uri must use https\");","typeGuard":"boolean isHttpsUrl(String url) {\n    try { return new java.net.URL(url).getProtocol().equalsIgnoreCase(\"https\"); } catch (Exception e) { return false; }\n}","tryCatchPattern":null,"preventionTips":["Always expose JWKS behind TLS and register the https URL","Use a tunneling service for local https endpoints during development","Never register internal http:// URLs against production authorization servers"],"tags":["oauth2","client-registration","jwks","https","security"],"backgroundTag":"invalid-url","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"}