{"record":{"id":"e220cf9b05311ee9","repo":"jwtk/jjwt","slug":"compact-jwt-strings-must-always-have-a-base64url-p","errorCode":null,"errorMessage":"Compact JWT strings MUST always have a Base64Url protected header per https://tools.ietf.org/html/rfc7519#section-7.2 (steps 2-4).","messagePattern":"Compact JWT strings MUST always have a Base64Url protected header per https://tools\\.ietf\\.org/html/rfc7519#section-7\\.2 \\(steps 2-4\\)\\.","errorType":"exception","errorClass":"MalformedJwtException","httpStatus":null,"severity":"error","filePath":"impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java","lineNumber":378,"sourceCode":"    }\n\n    @Override\n    public Jwt<?, ?> parse(Reader reader) {\n        Assert.notNull(reader, \"Reader cannot be null.\");\n        return parse(reader, Payload.EMPTY);\n    }\n\n    private Jwt<?, ?> parse(Reader compact, Payload unencodedPayload) {\n\n        Assert.notNull(compact, \"Compact reader cannot be null.\");\n        Assert.stateNotNull(unencodedPayload, \"internal error: unencodedPayload is null.\");\n\n        final TokenizedJwt tokenized = jwtTokenizer.tokenize(compact);\n        final CharSequence base64UrlHeader = tokenized.getProtected();\n        if (!Strings.hasText(base64UrlHeader)) {\n            String msg = \"Compact JWT strings MUST always have a Base64Url protected header per \" +\n                    \"https://tools.ietf.org/html/rfc7519#section-7.2 (steps 2-4).\";\n            throw new MalformedJwtException(msg);\n        }\n\n        // =============== Header =================\n        final byte[] headerBytes = decode(base64UrlHeader, \"protected header\");\n        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].)","sourceCodeStart":360,"sourceCodeEnd":396,"githubUrl":"https://github.com/jwtk/jjwt/blob/fb71496164c71442d08adec4571d9616ed5e1b8d/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java#L360-L396","documentation":"Every compact JWT must contain a Base64Url-encoded protected header as its first dot-separated segment per RFC 7519 §7.2. When tokenize() splits the compact string and the protected header segment is empty/blank, parse() throws MalformedJwtException.","triggerScenarios":"Calling parse/parseSignedClaims/parseSignedContent with a string missing the header segment: e.g. \".payload.signature\", \"..\", a bare signature, an empty string, or a truncated token cut at the first dot.","commonSituations":"Tokens truncated during logging/storage; string splitting or slicing bugs; passing authorization header values like 'Bearer ' prefix remnants or only the signature; reading tokens from config fields that are empty.","solutions":["Check the token is a complete three- (or five-) segment compact JWT before parsing","Strip any 'Bearer ' prefix and trim whitespace from the credential value","Fix upstream code (storage/logging) that truncates or loses the token"],"exampleFix":"// before\nString token = authHeader.split(\" \")[1]; // could yield partial token\n// after\nString token = authHeader.replaceFirst(\"^Bearer\\\\s+\", \"\").trim();\nif (token.chars().filter(c -> c == '.').count() != 2) throw new MalformedJwtException(\"bad token\");","handlingStrategy":"validation","validationCode":"if (token == null || token.chars().filter(c -> c == '.').count() != 2) {\n    throw new MalformedJwtException(\"Compact JWT must have 3 dot-separated segments\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    return parser.parseSignedClaims(token);\n} catch (MalformedJwtException e) {\n    throw new UnauthorizedException(\"Malformed JWT\", e);\n}","preventionTips":["Strip 'Bearer ' prefixes and trim before parsing","Validate segment count before calling parse","Never log/store truncated tokens as credentials"],"tags":["jwt","malformed-token","parsing"],"backgroundTag":"malformed-jwt","analyzedSha":"fb71496164c71442d08adec4571d9616ed5e1b8d","analyzedAt":"2026-09-09T00:33:09.982Z","contentChangedAt":"2026-09-09T00:33:09.982Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}