{"record":{"id":"f4b922de1f8dcd44","repo":"jwtk/jjwt","slug":"jwes-do-not-support-key-management-alg-header-valu","errorCode":null,"errorMessage":"JWEs do not support key management alg header value 'none' per https://www.rfc-editor.org/rfc/rfc7518.html#section-4.1","messagePattern":"JWEs do not support key management alg header value 'none' per https://www\\.rfc-editor\\.org/rfc/rfc7518\\.html#section-4\\.1","errorType":"exception","errorClass":"MalformedJwtException","httpStatus":null,"severity":"error","filePath":"impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java","lineNumber":409,"sourceCode":"\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())) {\n                String msg = String.format(CRIT_UNSECURED_MSG, header);\n                throw new MalformedJwtException(msg);\n            }\n        } else if (!hasDigest) { // something other than 'none'.  Must have a digest component:\n            String fmt = tokenized instanceof TokenizedJwe ? MISSING_JWE_DIGEST_MSG_FMT : MISSING_JWS_DIGEST_MSG_FMT;\n            String msg = String.format(fmt, alg);\n            throw new MalformedJwtException(msg);\n        }","sourceCodeStart":391,"sourceCodeEnd":427,"githubUrl":"https://github.com/jwtk/jjwt/blob/fb71496164c71442d08adec4571d9616ed5e1b8d/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java#L391-L427","documentation":"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.","triggerScenarios":"Calling parse(), parseSignedClaims(), or parseSignedContent() on a JWE compact string (5 segments, with an AAD-auth tag) whose protected header declares \"alg\":\"none\".","commonSituations":"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.","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."],"exampleFix":"// before: JWE built with alg=none (invalid)\nString jwe = Jwts.builder().claims(map)\n    .header().add(\"alg\", \"none\").and() /* ... */ .compact();\n\n// after: proper JWE encryption\nString jwe = Jwts.builder().claims(map)\n    .encryptWith(secretKey, Jwts.KEY.A128KW, Jwts.ENC.A128GCM)\n    .compact();","handlingStrategy":"validation","validationCode":"String headerJson = new String(java.util.Base64.getUrlDecoder().decode(token.split(\"\\\\.\")[0]), java.nio.charset.StandardCharsets.UTF_8);\nif (headerJson.contains(\"alg\\\":\\\"none\\\"\") && token.split(\"\\\\.\").length == 5) throw new IllegalArgumentException(\"JWE cannot use alg=none\");","typeGuard":null,"tryCatchPattern":"try { return parser.parse(jwe); }\ncatch (io.jsonwebtoken.MalformedJwtException e) { throw new InvalidTokenException(\"JWE declared alg=none\", e); }","preventionTips":["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"],"tags":["jwe","jwt","invalid-alg","malformed-token"],"backgroundTag":"invalid-enum-value","analyzedSha":"fb71496164c71442d08adec4571d9616ed5e1b8d","analyzedAt":"2026-09-09T00:33:09.982Z","contentChangedAt":"2026-09-09T00:33:09.982Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}