Skip to content
All tools
TokensRuns locallyNo account

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 ctfpal

A 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 fieldWhat it enables
algAlgorithm confusion, none bypass
kidPath traversal or SQL injection into key lookup
jku / x5uPoint key retrieval at a server you control
typRarely checked; occasionally a filter bypass

Worked example

A standard HS256 token

Input

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiZ3Vlc3QiLCJhZG1pbiI6ZmFsc2V9.7vN1kUnJ3nHfP_3Xf2X8sXJ7lPMlN3Sf

Result

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 workspace

Common 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.

Part of a module

6. Web attacks and session tokens

Read and forge JWTs and Flask sessions, find content nobody linked to, and probe for injection with detection payloads.

Practise on real challenges

Go deeper

Related tools