spring-projects/spring-security · error · OAuth2AuthenticationException
invalid_client_metadata
invalid_client_metadata
Error message
Invalid Client Registration: jwks_uri
What it means
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.
Source
Thrown at oauth2/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2ClientRegistrationAuthenticationValidator.java:208
catch (URISyntaxException ex) {
throw createException(OAuth2ErrorCodes.INVALID_REDIRECT_URI,
OAuth2ClientMetadataClaimNames.REDIRECT_URIS);
}
}
}
private static void validateJwkSetUri(OAuth2ClientRegistrationAuthenticationContext authenticationContext) {
OAuth2ClientRegistrationAuthenticationToken clientRegistrationAuthentication = authenticationContext
.getAuthentication();
URL jwkSetUrl = clientRegistrationAuthentication.getClientRegistration().getJwkSetUrl();
if (jwkSetUrl == null) {
return;
}
if (!"https".equalsIgnoreCase(jwkSetUrl.getProtocol())) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(LogMessage.format("Invalid request: jwks_uri does not use https ('%s')", jwkSetUrl));
}
throw createException("invalid_client_metadata", OAuth2ClientMetadataClaimNames.JWKS_URI);
}
}
private static void validateJwkSetUriSimple(OAuth2ClientRegistrationAuthenticationContext authenticationContext) {
// No validation. Preserves prior behavior.
}
private static void validateScope(OAuth2ClientRegistrationAuthenticationContext authenticationContext) {
OAuth2ClientRegistrationAuthenticationToken clientRegistrationAuthentication = authenticationContext
.getAuthentication();
List<String> scopes = clientRegistrationAuthentication.getClientRegistration().getScopes();
if (!CollectionUtils.isEmpty(scopes)) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(LogMessage.format(
"Invalid request: scope must not be set during Dynamic Client Registration ('%s')", scopes));
}
throw createException(OAuth2ErrorCodes.INVALID_SCOPE, OAuth2ClientMetadataClaimNames.SCOPE);
}View on GitHub (pinned to 96852e8860)
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
Example fix
// before
{"jwks_uri": "http://client.example.org/jwks.json"}
// after
{"jwks_uri": "https://client.example.org/jwks.json"} Defensive patterns
Strategy: validation
Validate before calling
if (jwksUri != null && !jwksUri.startsWith("https://")) throw new IllegalArgumentException("jwks_uri must use https"); Type guard
boolean isHttpsUrl(String url) {
try { return new java.net.URL(url).getProtocol().equalsIgnoreCase("https"); } catch (Exception e) { return false; }
} Prevention
- 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
When it happens
Trigger: POSTing a client registration whose jwks_uri is 'http://...' (plain HTTP) or otherwise non-https, e.g. 'http://client.example.org/jwks.json'.
Common situations: 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.
Understand the failure class
Background: "Invalid URL" / "URL cannot be empty": fix the malformed or missing URL behind request-construction failures — this error's family across 50 libraries.
Related errors
- Invalid Client Registration: + fieldName
- invalid_client_metadata
- missing_signature_verifier
- server_error
- Invalid Client Registration: + fieldName
AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10).
Data as JSON: /api/errors/ff8d0cf8176ed095.
Report an issue: GitHub.