jwtk/jjwt · error · MalformedJwtException
JWS header does not contain a required 'alg' (Algorithm) hea
Error message
JWS header does not contain a required 'alg' (Algorithm) header parameter. This header parameter is mandatory per the JWS Specification, Section 4.1.1. See https://www.rfc-editor.org/rfc/rfc7515.html#section-4.1.1 for more information.
What it means
jjwt rejects a compact JWT whose protected header is missing the mandatory 'alg' (Algorithm) header parameter required by RFC 7515 Section 4.1.1. During parse, the header's algorithm value is cleaned and checked; if empty, the token is malformed and cannot be processed, so a MalformedJwtException is thrown (with a JWE-specific message if the token is a JWE).
Source
Thrown at impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java:401
Map<String, ?> m = deserialize(Streams.of(headerBytes), "protected header");
Header header;
try {
header = tokenized.createHeader(m);
} catch (Exception e) {
String msg = "Invalid protected header: " + e.getMessage();
throw new MalformedJwtException(msg, e);
}
// 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())) {View on GitHub (pinned to fb71496164)
Solutions
- Regenerate the token with a compliant JWT library so the header includes a valid 'alg' value (e.g. via JwtBuilder.header().algorithm(...) or default builder behavior).
- Inspect the token's first base64url segment (decode it) to confirm whether 'alg' is present and non-empty before parsing.
- Fix the upstream issuer/serializer to always emit 'alg'; do not work around it by pre-editing tokens.
- If parsing third-party tokens, validate/verify the issuer's tokens are RFC 7515 compliant.
Example fix
// before (hand-built header without alg)
String token = base64Url("{"typ":"JWT"}") + "." + payload + "." + sig;
Jws<Claims> jws = Jwts.parser().verifyWith(key).build().parseSignedClaims(token);
// after (build with jjwt so alg is set automatically)
String token = Jwts.builder().subject("me")
.signWith(key, Jwts.SIG.HS256).compact(); Defensive patterns
Strategy: validation
Validate before calling
String[] parts = token.split("\\.");
String headerJson = new String(java.util.Base64.getUrlDecoder().decode(parts[0]), java.nio.charset.StandardCharsets.UTF_8);
if (!headerJson.contains("alg") || io.jsonwebtoken.lang.Strings.hasText(headerJson.replace("alg", "").trim()) == false) throw new IllegalArgumentException("token header missing alg"); Try / catch
try { return parser.parseSignedClaims(token); }
catch (io.jsonwebtoken.MalformedJwtException e) { log.warn("Token missing alg header", e); throw new InvalidTokenException(e); } Prevention
- Always build tokens with JwtBuilder so alg is emitted automatically
- Never hand-assemble compact JWT strings
- Validate issuer tokens once in an integration test
- Decode and inspect the header segment when debugging parse failures
When it happens
Trigger: Calling JwtParser.parse(), parseSignedContent(), or parseSignedClaims() on a compact token whose protected header either omits 'alg' entirely or has an empty/whitespace-only 'alg' value.
Common situations: Hand-constructed or manually base64url-encoded tokens; tokens produced by a custom or buggy serializer that drops the alg field; truncated/corrupted tokens where header JSON was altered; third-party token issuers that emit non-compliant headers.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- Protected Header crit set references header name '%s', but t
- The JWS header references signature algorithm 'none' yet the
- Unsecured JWSs (those with an alg header value of 'none') ma
- Unexpected content JWS.
- Unexpected Claims JWS.
AI-assisted analysis of jwtk/jjwt@fb71496164 (2026-09-09).
Data as JSON: /api/errors/dc6da866031d9f6a.
Report an issue: GitHub.