JWT decoder and signature verifier
Decode a JSON Web Token’s header and payload and verify HS256/HS384/HS512 signatures against a known secret - all locally.
Open in ctfpalA JWT is three Base64-URL segments joined by dots: header, payload, signature. The first two are not encrypted - anyone holding the token can read the claims. The signature is the only thing standing between a user and an admin claim, which is why every JWT challenge is really a question about how the signature is checked.
Read the header first
The header names the algorithm, and that name is the attack surface. alg: HS256 means a shared secret - crackable if it is weak. alg: RS256 means a public key - and an implementation that lets you switch it to HS256 will verify the signature using the public key as an HMAC secret, which you already have. alg: none means no verification at all.
| Header field | What it enables |
|---|---|
alg | Algorithm confusion, none bypass |
kid | Path traversal or SQL injection into key lookup |
jku / x5u | Point key retrieval at a server you control |
typ | Rarely checked; occasionally a filter bypass |
Worked example
A standard HS256 token
Input
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiZ3Vlc3QiLCJhZG1pbiI6ZmFsc2V9.7vN1kUnJ3nHfP_3Xf2X8sXJ7lPMlN3SfResult
Header {"alg":"HS256","typ":"JWT"}, payload {"user":"guest","admin":false}The `admin: false` claim is readable and, without signature verification, editable.
Load this example in the workspaceCommon questions
- Can I edit a JWT payload?
- You can always edit it; whether the server accepts it depends on signature verification. That is exactly what the [none-algorithm](/tools/jwt-none-algorithm) and [secret brute force](/tools/jwt-secret-bruteforce) pages are about.