{"record":{"id":"22676b45474f49ab","repo":"jwtk/jjwt","slug":"jwe-header-does-not-contain-a-required-alg-algo","errorCode":null,"errorMessage":"JWE header does not contain a required 'alg' (Algorithm) header parameter.  This header parameter is mandatory per the JWE Specification, Section 4.1.1. See https://www.rfc-editor.org/rfc/rfc7516.html#section-4.1.1 for more information.","messagePattern":"JWE header does not contain a required 'alg' \\(Algorithm\\) header parameter\\.  This header parameter is mandatory per the JWE Specification, Section 4\\.1\\.1\\. See https://www\\.rfc-editor\\.org/rfc/rfc7516\\.html#section-4\\.1\\.1 for more information\\.","errorType":"exception","errorClass":"MalformedJwtException","httpStatus":null,"severity":"error","filePath":"impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java","lineNumber":401,"sourceCode":"        Map<String, ?> m = deserialize(Streams.of(headerBytes), \"protected header\");\n        Header header;\n        try {\n            header = tokenized.createHeader(m);\n        } catch (Exception e) {\n            String msg = \"Invalid protected header: \" + e.getMessage();\n            throw new MalformedJwtException(msg, e);\n        }\n\n        // https://tools.ietf.org/html/rfc7515#section-10.7 , second-to-last bullet point, note the use of 'always':\n        //\n        //   *  Require that the \"alg\" Header Parameter be carried in the JWS\n        //      Protected Header.  (This is always the case when using the JWS\n        //      Compact Serialization and is the approach taken by CMS [RFC6211].)\n        //\n        final String alg = Strings.clean(header.getAlgorithm());\n        if (!Strings.hasText(alg)) {\n            String msg = tokenized instanceof TokenizedJwe ? MISSING_JWE_ALG_MSG : MISSING_JWS_ALG_MSG;\n            throw new MalformedJwtException(msg);\n        }\n        final boolean unsecured = Jwts.SIG.NONE.getId().equalsIgnoreCase(alg);\n\n        final CharSequence base64UrlDigest = tokenized.getDigest();\n        final boolean hasDigest = Strings.hasText(base64UrlDigest);\n        if (unsecured) {\n            if (tokenized instanceof TokenizedJwe) {\n                throw new MalformedJwtException(JWE_NONE_MSG);\n            }\n            // Unsecured JWTs are disabled by default per the RFC:\n            if (!this.unsecured) {\n                String msg = UNSECURED_DISABLED_MSG_PREFIX + header;\n                throw new UnsupportedJwtException(msg);\n            }\n            if (hasDigest) {\n                throw new MalformedJwtException(JWS_NONE_SIG_MISMATCH_MSG);\n            }\n            if (header.containsKey(DefaultProtectedHeader.CRIT.getId())) {","sourceCodeStart":383,"sourceCodeEnd":419,"githubUrl":"https://github.com/jwtk/jjwt/blob/fb71496164c71442d08adec4571d9616ed5e1b8d/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java#L383-L419","documentation":"The JWE specification (RFC 7516 §4.1.1) mandates an 'alg' (Algorithm) header parameter identifying the key-management algorithm. When parsing a tokenized JWE whose header lacks a usable 'alg' value, parse() throws MalformedJwtException with this message (distinguished from the JWS variant via MISSING_JWE_ALG_MSG).","triggerScenarios":"Parsing an encrypted JWT (five-segment compact form) whose protected header omits 'alg' or has an empty/whitespace-only value — typically a token produced by a non-compliant encryptor or a hand-assembled header.","commonSituations":"Custom/buggy encryption code building headers manually; other libraries that place 'alg' in the unprotected (shared) header instead of the protected header; tokens mutated so header fields were dropped.","solutions":["Fix the token producer to include 'alg' in the protected header (e.g. Jwts.builder().header().algorithm(...)).encryptWith(...)","Decode the first segment of the failing token to confirm 'alg' is missing and reject such tokens at the boundary","If another library produced the token, configure it to put alg/enc in the protected header per RFC 7516"],"exampleFix":"// before\nString jwe = Jwts.builder().setClaims(claims)\n    .encryptWith(key, encAlg).compact(); // no alg header\n// after\nString jwe = Jwts.builder().setClaims(claims)\n    .header().add(\"alg\", keyAlg.getId()).and()\n    .encryptWith(key, keyAlg, encAlg).compact();","handlingStrategy":"validation","validationCode":"String headerJson = new String(Base64.getUrlDecoder().decode(token.split(\"\\\\.\")[0]), StandardCharsets.UTF_8);\nif (!headerJson.contains(\"\\\"alg\\\"\")) {\n    throw new MalformedJwtException(\"JWE header missing required 'alg'\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    return parser.parseEncryptedClaims(token, decryptKey);\n} catch (MalformedJwtException e) {\n    if (e.getMessage().contains(\"'alg'\")) {\n        throw new UnauthorizedException(\"Non-compliant JWE: missing alg\", e);\n    }\n    throw e;\n}","preventionTips":["Always build JWEs with the library's encryptWith(...) so mandatory headers are set","Verify third-party producers emit RFC 7516 compliant protected headers","Validate presence of alg/enc in header during token intake"],"tags":["jwt","jwe","missing-header"],"backgroundTag":"missing-required-argument","analyzedSha":"fb71496164c71442d08adec4571d9616ed5e1b8d","analyzedAt":"2026-09-09T00:33:09.982Z","contentChangedAt":"2026-09-09T00:33:09.982Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}