spring-projects/spring-security · error · BadJwtException
Unsupported alg parameter in JWS Header: ${algorithm.getName
Error message
Unsupported alg parameter in JWS Header: ${algorithm.getName()} What it means
This BadJwtException is thrown by DPoPProofJwtDecoderFactory's jwsKeySelector when the DPoP proof JWT's JWS header declares an algorithm outside the RSA or EC families (e.g. HS256 or none). The factory only accepts asymmetric RSA/EC algorithms, per RFC 9449, and rejects everything else before key selection.
Source
Thrown at oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/DPoPProofJwtDecoderFactory.java:183
return delegatingTokenValidator;
}
private static NimbusJwtDecoder buildDecoder() {
ConfigurableJWTProcessor<SecurityContext> jwtProcessor = new DefaultJWTProcessor<>();
jwtProcessor.setJWSTypeVerifier(DPOP_TYPE_VERIFIER);
jwtProcessor.setJWSKeySelector(jwsKeySelector());
// Override the default Nimbus claims set verifier and use jwtValidatorFactory for
// claims validation
jwtProcessor.setJWTClaimsSetVerifier((claims, context) -> {
});
return new NimbusJwtDecoder(jwtProcessor);
}
private static JWSKeySelector<SecurityContext> jwsKeySelector() {
return (header, context) -> {
JWSAlgorithm algorithm = header.getAlgorithm();
if (!JWSAlgorithm.Family.RSA.contains(algorithm) && !JWSAlgorithm.Family.EC.contains(algorithm)) {
throw new BadJwtException("Unsupported alg parameter in JWS Header: " + algorithm.getName());
}
JWK jwk = header.getJWK();
if (jwk == null) {
throw new BadJwtException("Missing jwk parameter in JWS Header.");
}
if (jwk.isPrivate()) {
throw new BadJwtException("Invalid jwk parameter in JWS Header.");
}
try {
if (JWSAlgorithm.Family.RSA.contains(algorithm) && jwk instanceof RSAKey rsaKey) {
return Collections.singletonList(rsaKey.toRSAPublicKey());
}
else if (JWSAlgorithm.Family.EC.contains(algorithm) && jwk instanceof ECKey ecKey) {
return Collections.singletonList(ecKey.toECPublicKey());
}
}View on GitHub (pinned to 96852e8860)
Solutions
- Use RS256/RS384/RS512, ES256/ES384/ES512, or PS* algorithms when creating the DPoP proof (e.g. RSA JWS signer or ECDSASigner in Nimbus).
- Catch BadJwtException on decode and return a 401 invalid_dpop_proof error.
- If you control the client config, ensure its DPoP signer matches RSA or EC keys.
- Verify the proof header is produced by a DPoP library, not hand-rolled JWT code defaulting to HS256.
Example fix
// before JWSSigner signer = new MACSigner(secret); // produces HS256 -> rejected // after JWSSigner signer = new RSASSASigner(rsaKey); // RS256, accepted
Defensive patterns
Strategy: validation
Validate before calling
Set<JWSAlgorithm> allowed = new HashSet<>();
allowed.addAll(JWSAlgorithm.Family.RSA);
allowed.addAll(JWSAlgorithm.Family.EC);
if (!allowed.contains(header.getAlgorithm())) { throw new IllegalArgumentException("alg not allowed"); } Type guard
boolean isRsaOrEc(JWSAlgorithm alg) {
return JWSAlgorithm.Family.RSA.contains(alg) || JWSAlgorithm.Family.EC.contains(alg);
} Try / catch
try {
Jwt jwt = decoder.decode(proof);
} catch (BadJwtException ex) {
throw new OAuth2AuthorizationCodeException(...); // respond 401 invalid_dpop_proof
} Prevention
- Sign DPoP proofs with RSA or EC keys only — never HMAC (HS256).
- Add a header-alg assertion in your client's proof-generation tests.
- Reject 'none' and symmetric algs at the client boundary.
When it happens
Trigger: Decoding a DPoP proof JWT whose JOSE header alg is not in JWSAlgorithm.Family.RSA or Family.EC (e.g. HS256, PS-misconfigured variants are fine, but HS256/others throw).
Common situations: A client signs the proof with HS256 (symmetric), uses 'none', or an older client library defaults to a non-RSA/EC algorithm; or a malicious/misrouted JWT is fed to the DPoP decoder.
Related errors
- invalid_dpop_proof
- Missing jwk parameter in JWS Header.
- invalid_dpop_proof
- invalid_key
- invalid_algorithm
AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10).
Data as JSON: /api/errors/6931436ab2c69b8e.
Report an issue: GitHub.