How to Validate JWT Tokens by Checking Their Structure
Validate JWT tokens in bulk by checking their structure - three base64url segments split by dots. Catch malformed tokens fast, and know why structure-valid is not signature-verified.
How to Validate JWT Tokens by Checking Their Structure
A JWT looks like one long opaque string, but it has a strict shape. When you paste a column of tokens out of a log file, a CSV export, or a support ticket, half the cleanup work is just spotting which ones are not even tokens. A truncated copy-paste, a trailing space, a row that got cut at a comma - these never make it past the parser, and you want them flagged before they reach an allowlist or an import script.
That is exactly what the JWT Token List Validator does. It runs in your browser tab, reads each line as a candidate token, and prints a pass/fail report with a reason beside every row. This post is about what "valid structure" really means, what the tool checks, and the one thing it deliberately does not do.
What a structurally valid JWT actually is
Here is the concrete rule, and it is the whole basis of structural validation:
A structurally valid JWT is three base64url-encoded segments joined by dots - header.payload.signature. Three parts, two dots, and every character inside a part has to come from the base64url alphabet: A-Z, a-z, 0-9, -, and _. No standard + or /, no padding =, no spaces.
From that single rule you can already see what counts as malformed:
- A token with only two segments (
header.payload) is malformed - a signature segment is missing. - A token with four segments is not a plain JWT either.
- A segment containing a non-base64url character - a
+, a/, a space, a stray quote from a CSV cell - is malformed. - An empty segment (two dots in a row,
header..signature) is malformed.
None of this requires decoding the payload or knowing your secret. The shape alone tells you whether the string is a candidate token or garbage that needs to go back to whoever sent it.
Structure-valid is not signature-verified
This is the part people misread, so I will say it plainly: passing the structure check does not mean the signature is valid, and it does not mean the token is unexpired.
The tool checks the shape - three base64url segments separated by dots. It does not verify the signature. It has no access to your signing key, it does not recompute the HMAC or check the RSA signature, and it does not read the exp claim to see whether the token has expired. A token that someone hand-typed, or one whose payload was edited, can be perfectly well-formed and completely untrustworthy.
So a "pass" here means one specific thing: this string is shaped like a JWT and could be parsed by something that knows the key. It is the cheap first gate. The expensive gate - actually verifying the signature against your key and checking expiry - happens later, in the service that owns the secret. Structural validation just stops you from feeding obviously broken strings into that service in the first place.
The tool's own FAQ is blunt about it, and the common mistakes note repeats the point: do not treat structural validation as proof that the account, domain, or token behind the string is real or current.
A worked example
Say a teammate hands you this list pulled from a few different places, and asks which rows are safe to import:
eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0In0.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiI5OTkifQ
eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhYmMrZGVmIn0=.c2lnbmF0dXJl
eyJhbGciOiJIUzI1NiJ9..dBjftJeZ4CVP
eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiI3In0.VGhpc0lzQVZhbGlkTG9va2luZ1NpZw
Run it through the validator and the report comes back row by row:
| Row | Result | Reason | | --- | --- | --- | | 1 | pass | three base64url segments, two dots | | 2 | fail | only two segments - signature part missing | | 3 | fail | contains + and =, not base64url | | 4 | fail | empty middle segment (payload) | | 5 | pass | three base64url segments, two dots |
Two rows pass the structure check; three are flagged with the exact reason next to them. Notice rows 1 and 5 only "pass" structurally - neither has been signature-verified, and you still do not know if they are expired. Rows 2, 3, and 4 are the ones you hand back to be fixed, which is the real payoff: the fail list, with reasons, is the artifact you act on.
What the tool gives you beyond the check
The validator is built for cleanup that ends in a handoff, so it does more than mark rows. Everything below runs locally in the tab - nothing is sent to a server, and uploaded text files are read with the browser File API.
- Keep unique rows only, or preserve the invalid rows for review. The whole point is the fail list, so invalid rows stay in the report with their reason rather than being quietly dropped.
- Sort the normalized output so the artifact is stable.
- Export to CSV, JSON, Markdown, SQL
IN, TypeScript union, or plain lines - whatever your next step expects. - Sensitive masking: JWTs are treated as sensitive, so the output masks the token value while still giving you the pass/fail signal. You get a checkable report without spraying live tokens across a CSV.
When I am cleaning a list like this, I always export the CSV with line numbers rather than copying the final pass list by itself. The first time I skipped that, a teammate asked why three tokens had been "removed," and I had no record of which rows failed or why. With the line-numbered report, the answer is right there: row 2 was missing its signature segment, row 3 had a +. That audit trail is worth the extra click every single time.
Where it fits with the other tools
Structural validation is one stage in a pipeline. If the tokens are buried in noise, pull them out with the JWT Token Extractor first, then validate. If your list has hidden whitespace or inconsistent casing, run the JWT Token Normalizer before validating, since copied web text often carries invisible characters that quietly break the base64url check. To collapse repeats, hand the result to the JWT Token Deduplicator, and when you need the clean list in a specific format, the JWT Token List Converter turns it into JSON, SQL IN, or a TypeScript union.
For non-token lists, the same browser-local approach shows up in the HTTP Header Extractor and the Base64 Block Extractor. Same idea throughout: check the structure locally, keep the reasons, hand off a clean artifact.
Structural validation is fast, it is honest about its limits, and it catches the broken strings that would otherwise fail much later in a place that is harder to debug. Run it as the cheap first gate, then let the service that holds your key do the real signature and expiry check.
Made by Toolora · Updated 2026-06-13