jwtk/jjwt · error · MalformedJwtException
JWEs do not support key management alg header value 'none' p
Error message
JWEs do not support key management alg header value 'none' per https://www.rfc-editor.org/rfc/rfc7518.html#section-4.1
What it means
jjwt rejects JWE compact strings whose key management 'alg' header is 'none'. Per RFC 7518 Section 4.1, JWE key management algorithms never include 'none' — unsecured (algorithm-none) tokens are only valid as JWS, never as encrypted JWEs. The parser detects a TokenizedJwe whose alg equals 'none' and throws MalformedJwtException.
Source
Thrown at impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java:409
// https://tools.ietf.org/html/rfc7515#section-10.7 , second-to-last bullet point, note the use of 'always':
//
// * Require that the "alg" Header Parameter be carried in the JWS
// Protected Header. (This is always the case when using the JWS
// Compact Serialization and is the approach taken by CMS [RFC6211].)
//
final String alg = Strings.clean(header.getAlgorithm());
if (!Strings.hasText(alg)) {
String msg = tokenized instanceof TokenizedJwe ? MISSING_JWE_ALG_MSG : MISSING_JWS_ALG_MSG;
throw new MalformedJwtException(msg);
}
final boolean unsecured = Jwts.SIG.NONE.getId().equalsIgnoreCase(alg);
final CharSequence base64UrlDigest = tokenized.getDigest();
final boolean hasDigest = Strings.hasText(base64UrlDigest);
if (unsecured) {
if (tokenized instanceof TokenizedJwe) {
throw new MalformedJwtException(JWE_NONE_MSG);
}
// Unsecured JWTs are disabled by default per the RFC:
if (!this.unsecured) {
String msg = UNSECURED_DISABLED_MSG_PREFIX + header;
throw new UnsupportedJwtException(msg);
}
if (hasDigest) {
throw new MalformedJwtException(JWS_NONE_SIG_MISMATCH_MSG);
}
if (header.containsKey(DefaultProtectedHeader.CRIT.getId())) {
String msg = String.format(CRIT_UNSECURED_MSG, header);
throw new MalformedJwtException(msg);
}
} else if (!hasDigest) { // something other than 'none'. Must have a digest component:
String fmt = tokenized instanceof TokenizedJwe ? MISSING_JWE_DIGEST_MSG_FMT : MISSING_JWS_DIGEST_MSG_FMT;
String msg = String.format(fmt, alg);
throw new MalformedJwtException(msg);
}View on GitHub (pinned to fb71496164)
Solutions
- If the token is meant to be unsecured, emit it as a JWS (3 segments) with alg=none and parse with parser builder configured via unsecured().
- If the token is meant to be encrypted, set a real JWE key-management algorithm (e.g. RSA-OAEP-256, A128KW) via Jwts.builder().encryptWith(key, alg, enc).
- Verify the token's structure (count dot-separated segments) to confirm whether it is a JWS or JWE and use the appropriate parse method.
- Fix the issuing service so it never produces alg=none JWEs.
Example fix
// before: JWE built with alg=none (invalid)
String jwe = Jwts.builder().claims(map)
.header().add("alg", "none").and() /* ... */ .compact();
// after: proper JWE encryption
String jwe = Jwts.builder().claims(map)
.encryptWith(secretKey, Jwts.KEY.A128KW, Jwts.ENC.A128GCM)
.compact(); Defensive patterns
Strategy: validation
Validate before calling
String headerJson = new String(java.util.Base64.getUrlDecoder().decode(token.split("\\.")[0]), java.nio.charset.StandardCharsets.UTF_8);
if (headerJson.contains("alg\":\"none\"") && token.split("\\.").length == 5) throw new IllegalArgumentException("JWE cannot use alg=none"); Try / catch
try { return parser.parse(jwe); }
catch (io.jsonwebtoken.MalformedJwtException e) { throw new InvalidTokenException("JWE declared alg=none", e); } Prevention
- Use encryptWith(...) with a real JWE key algorithm; never set alg=none on encrypted tokens
- Remember: alg=none is a JWS-only concept
- Check token shape (3 segments = JWS, 5 = JWE) before parsing
- Audit custom serializers for hardcoded alg headers
When it happens
Trigger: Calling parse(), parseSignedClaims(), or parseSignedContent() on a JWE compact string (5 segments, with an AAD-auth tag) whose protected header declares "alg":"none".
Common situations: Custom token builders that mistakenly set alg=none on encrypted tokens; confusion between unsecured JWS and JWE formats; hand-rolled JWE serialization copying a JWS 'none' header; misconfigured issuer that disables encryption but still emits JWE structure.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- The JWE header references key management algorithm '%s' but
- Compact JWE strings MUST always contain a payload (ciphertex
- Unexpected content JWE.
- Unexpected Claims JWE.
- PrivateKeys may not be used to encrypt data. PublicKeys are
AI-assisted analysis of jwtk/jjwt@fb71496164 (2026-09-09).
Data as JSON: /api/errors/f4b922de1f8dcd44.
Report an issue: GitHub.