spring-projects/spring-security · error · BadJwtException
Unsupported algorithm of + jwt.getHeader().getAlgorithm()
Error message
Unsupported algorithm of + jwt.getHeader().getAlgorithm()
What it means
Inside the JwkSourceReactiveJwtDecoderBuilder's processor, if the decoded token is not a SignedJWT (i.e. it is an unsecured/JWE token or uses an unexpected header), the decoder cannot select a JWK for it and throws BadJwtException('Unsupported algorithm of <alg>'). It guards the jwkSource path so only JWS-signed tokens the configured algorithms apply to reach key selection.
Solutions
- Check the token header alg and ensure the decoder's jwsAlgorithms includes it
- Ensure the issuer produces SignedJWTs (signed, not encrypted or unsecured tokens)
- Use NimbusJwtDecoder/NimbusReactiveJwtDecoder withJweDecoder support if encrypted tokens are the real input
- Regenerate a valid signed test token from the Authorization Server
Example fix
// before
JWSAlgorithm expected = JWSAlgorithm.HS256; // token actually uses ES256
// after
JWSAlgorithm expected = JWSAlgorithm.ES256;
NimbusReactiveJwtDecoder decoder = NimbusReactiveJwtDecoder.withJwkSource(jwkSource)
.jwsAlgorithm(SignatureAlgorithm.ES256).build(); Defensive patterns
Strategy: try-catch
Validate before calling
// confirm token is a SignedJWT with expected alg before calling the decoder
String[] parts = jwt.split("\\.");
if (parts.length != 3) throw new IllegalArgumentException("Not a JWS (3 segments expected)"); Try / catch
try {
Jwt jwt = decoder.decode(token);
} catch (BadJwtException e) {
log.warn("Token not a supported signed JWT: {}", e.getMessage());
throw new UnauthorizedException("Unsupported token type/algorithm");
} Prevention
- Only feed signed JWS tokens to jwkSource-based decoders
- Align jwsAlgorithm() with what the issuer actually signs with
- Never test with alg=none or hand-crafted tokens against production decoders
When it happens
Trigger: Calling NimbusReactiveJwtDecoder.withJwkSource(...) and feeding it a token whose header alg does not match the configured jwsAlgorithms (so Nimbus decodes it as something other than a SignedJWT path), or an unsecured/alg=none or encrypted token is passed to a decoder meant for signed JWS tokens.
Common situations: Sending JWE (encrypted) tokens to a decoder expecting signed JWTs; an issuer switching to alg=none or a non-signing token type; misconfigured jwsAlgorithms so the processor falls through to this throw; testing with hand-crafted tokens.
Related errors
- Unsupported algorithm of + header.getAlgorithm()
- missing_signature_verifier
- An error occurred while attempting to decode the Jwt: +…
- Failed to encode the JWT due to signing error: Failed to…
- Failed to validate the token
AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10).
Data as JSON: /api/errors/158cb2f7a76f2aff.
Report an issue: GitHub.
Appendix: source
Thrown at oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusReactiveJwtDecoder.java:943
Converter<JWT, Mono<JWTClaimsSet>> processor() {
JWKSecurityContextJWKSet jwkSource = new JWKSecurityContextJWKSet();
JWSKeySelector<JWKSecurityContext> jwsKeySelector = new JWSVerificationKeySelector<>(this.jwsAlgorithm,
jwkSource);
DefaultJWTProcessor<JWKSecurityContext> jwtProcessor = new DefaultJWTProcessor<>();
jwtProcessor.setJWSKeySelector(jwsKeySelector);
jwtProcessor.setJWSTypeVerifier(this.typeVerifier);
jwtProcessor.setJWTClaimsSetVerifier((claims, context) -> {
});
this.jwtProcessorCustomizer.accept(jwtProcessor);
return (jwt) -> {
if (jwt instanceof SignedJWT) {
return this.jwkSource.apply((SignedJWT) jwt)
.onErrorMap((e) -> new IllegalStateException("Could not obtain the keys", e))
.collectList()
.map((jwks) -> createClaimsSet(jwtProcessor, jwt, new JWKSecurityContext(jwks)));
}
throw new BadJwtException("Unsupported algorithm of " + jwt.getHeader().getAlgorithm());
};
}
}
}
View on GitHub (pinned to 96852e8860)