Decode a JSON Web Token (JWT)
- Dashboard
- Documentation
- API
What is a JWT (JSON Web Token)?
A JSON Web Token, abbreviated as JWT (pronounced "jot"), is a compact format defined by RFC 7519 for transporting a series of claims between two parties. The JWT is today the dominant format to carry an authenticated identity in an HTTP API. A JWT looks like an ASCII string made of three segments separated by dots:
header.payload.signature
Each segment is encoded in Base64URL, a variant of Base64 without
= padding and that replaces + with - and / with _
so that it can travel in a URL or an HTTP header without further escaping.
Important: a JWT is NOT encrypted. The standard JWT format (JWS) is simply signed: the signature guarantees the content's integrity, but provides no confidentiality. Anyone can decode the payload of a JWT with a simple inverse Base64URL, as does this online jwt decode tool.
Anatomy of a JWT
A JSON Web Token is composed of three distinct parts, each playing a precise role in the authentication mechanism:
1. Header
The header is a JSON object that describes how the token is signed. It contains at least:
alg(algorithm): the signature algorithm used. Typical values:HS256,RS256,ES256,EdDSA.typ(type): the token type, almost always"JWT".kid(key ID): optional, identifies which key should be used to verify the signature. Useful when there is a pool of keys in rotation (JWKS).
2. Payload
The payload contains the claims, that is, the assertions the issuer makes about the user or the session. RFC 7519 defines seven standard claims (registered claims):
iss(issuer): who issued the token, for example"https://accounts.google.com".sub(subject): who the token belongs to, in practice the user identifier.aud(audience): who the token is intended for. Prevents a token issued for API A from being accepted by API B.exp(expiration time): Unix timestamp after which the token is no longer valid.nbf(not before): timestamp before which the token is not yet active.iat(issued at): token issuance timestamp.jti(JWT ID): unique identifier of the token, used for revocation and replay prevention.
On top of these standard claims, applications usually add custom claims
(roles, scope, tenant_id, email,
permissions...).
3. Signature
The signature is a cryptographic digest computed over
base64url(header) + "." + base64url(payload) using a key. It is what proves
that no one has modified the header or the payload since issuance. The most common algorithms:
- HS256 / HS384 / HS512: symmetric HMAC-SHA signature. A secret key shared between issuer and verifier. Simple, but unsuited as soon as there is more than one consumer.
- RS256 / RS384 / RS512: asymmetric RSA signature. The issuer signs with its private key, any consumer verifies with the matching public key. De facto standard for OAuth2 and OpenID Connect.
- ES256 / ES384 / ES512: asymmetric ECDSA signature. Same properties as RS256 but with much shorter keys and signatures.
- EdDSA (Ed25519): modern asymmetric signature, fast and compact.
Again: the signature protects integrity, not confidentiality. The payload remains readable by anyone who has the token.
Why decode a JWT?
The jwt token decode operation answers several concrete needs for a developer or a security engineer:
- Authentication debugging: your API returns a 401 or 403, you want to see
what is actually in the payload (
sub,scope,roles,exp) rather than guess. - Verify the claims: confirm that a token does contain the expected
claim (for example
tenant_idorpermissions) before looking elsewhere in the authorisation chain. - Read the expiry: convert the
exptimestamp to a human date to confirm that a token is indeed expired, or on the contrary that it should still be valid. - Security audit: ensure that a third-party service does not leak sensitive information in the payload (emails, internal identifiers, personal data).
- Training and understanding: see concretely what a JSON Web Token coming out of an OAuth provider (Google, Auth0, Keycloak, AWS Cognito) looks like to grasp the mechanics without diving into the docs.
- Public token exploration: inspect a JWT found in logs, in a cookie or in an interceptable OAuth exchange.
Decoder vs Verifier: the critical distinction
The two operations look similar but they have nothing to do with each other in terms of security guarantees:
- Decoding a JWT means splitting the string on the
.and applying inverse Base64URL to the first two segments. It is a simple read, within reach of any three-line script. No signature verification is performed. - Verifying a JWT means recomputing the signature from the header, the payload and a key, then comparing the result to the signature present in the token. That is what guarantees the token has not been tampered with.
Practical conclusion: decoding does not mean trusting. Until the signature has been verified with the right key, the payload content can be totally bogus. For the trust phase, use our JWT Verifier.
How to use it
- Grab the JWT to inspect, for example from an
Authorization: Bearer <jwt>header, from a session cookie, from the browser'slocalStorage, or from an application log. - Paste the full string into the input field. The three segments must stay separated by dots.
- The tool immediately displays the decoded header as formatted JSON, with the algorithm and the type.
- The payload is then decoded and displayed. You see every standard and custom claim there.
- The tool also reports the signature information (declared algorithm, length), without verifying it.
- To confirm the token has not been tampered with, switch to our JWT Verifier with the expected public key or secret.
The entire decoding runs in your browser in JavaScript: your token is never sent to our servers.
JWT and security: pitfalls to avoid
NEVER store sensitive data in the payload of a signed JWT.
Passwords, credit card numbers, medical data, API secrets, critical internal identifiers: everything in the payload is readable by anyone who has the token, including the user via the browser's developer tools. The signature hides nothing, it merely proves that the issuer is who it claims to be.
A few golden rules to use JWTs properly in production:
- Always verify the signature server-side before granting any right. Our JWT Verifier illustrates exactly that operation.
- Prefer RS256 or ES256 to HS256 for public APIs. Asymmetric signing avoids sharing a secret between the issuer and each consumer.
- Always respect the
expclaim. A JWT without expiry or with an overly distant expiry is a time bomb in case of a leak. - Validate
issandaudserver-side, to prevent a legitimate token issued for another service from being accepted by mistake. - Refuse
alg: "none"on verification. It is a classic flaw that lets an attacker forge any payload. - Keep lifetimes short (15 minutes for example) and pair with a longer but server-side revocable refresh token.
Example of a decoded JWT
Here is a typical JWT:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjMiLCJuYW1lIjoiSm9obiIsImlhdCI6MTUxNjIzOTAyMn0.jrU9j8LZcRK2_BZjqXjU7lEpJbkqmXfTQIu9vT45j-I
Once decoded, here is its content:
// Header
{
"alg": "HS256",
"typ": "JWT"
}
// Payload
{
"sub": "123",
"name": "John",
"iat": 1516239022
}
// Signature (binary, encoded in Base64URL)
HMACSHA256(
base64url(header) + "." + base64url(payload),
secret
)
Where to find a JWT to copy?
In practice, a JWT to decode most often comes from one of these locations:
- HTTP cookie: open the developer tools (F12), Application
or Storage tab, then Cookies. Look for a cookie named
access_token,jwt,sessionor similar. localStorage/sessionStorage: same panel, Local Storage section. Many SPAs store their token there under atokenorauthkey.Authorizationheader: Network tab, pick an API request, read theAuthorization: Bearer <jwt>header. Copy only the part afterBearer.- Server logs: a JWT sometimes appears in the logs of a gateway or a reverse proxy (to avoid in production, but useful for debugging).
Frequently asked questions
Is the JWT encrypted or in clear?
A signed JWT (JWS format) is only Base64URL-encoded, not encrypted. Anyone who intercepts a token can read the payload in seconds. If you need to carry truly confidential data in the token, you must use the JWE format (JSON Web Encryption), which adds an encryption layer on top of the signature. In practice, JWE remains rare: it is preferred to not put sensitive data in a token and to keep critical information in a database server-side.
How do I revoke a JWT before its expiry?
This is one of the weaknesses of JWT: by design, the server does not need to store
the token's state, so it does not know how to mark it revoked either. Three approaches
exist. Revocation list: maintain server-side the list of invalidated
jtis, and consult it on every request. Short lifetimes:
issue access tokens valid for 5 to 15 minutes, and use a server-side revocable refresh token
to generate new ones. Signing key rotation: invalidate
a whole generation of tokens by changing the key. The second approach is by far the most
widespread.
What is the difference between a JWT and a classic session?
A classic session stores an opaque identifier client-side (usually in a cookie) and keeps all associated data (user, rights, expiry) in memory or in a database server-side. A JWT, on the contrary, carries this data directly in the signed token. JWT advantage: the server does not need to store a session, which simplifies horizontal scaling and microservices architecture. Drawbacks: revocation is more complex, the token is bigger on every request, and the smallest leak exposes the payload.
Difference between JWT, JWS and JWE?
JWT (RFC 7519) is a generic token format. It can be implemented in two concrete ways: JWS (RFC 7515, JSON Web Signature) which just signs the payload, and JWE (RFC 7516, JSON Web Encryption) which encrypts it. In practice, when one says "JWT" without qualification, one almost always means a JWS: a signed but readable-by-all token. JWE is used in contexts where the payload's confidentiality is essential, for example in some advanced OpenID Connect scenarios.
My JWT is not accepted by the API, why?
The classic causes are, in frequency order: expired token (check
the exp claim), invalid signature (the secret or public key
does not match the one used by the issuer), wrong aud
(the token was issued for another service), wrong iss
(the declared issuer is not the expected one), refused algorithm (the API
requires RS256 for example and receives HS256), clock skew between
issuer and verifier (affects exp and nbf). Decoding the
token with this tool already eliminates half the hypotheses by reading the
claims directly.
How do I generate a JWT?
Most languages have a dedicated library: jsonwebtoken in
Node.js, PyJWT in Python, lcobucci/jwt or
firebase/php-jwt in PHP, jjwt in Java, golang-jwt/jwt
in Go. They all take a payload object, a key and an algorithm as input, and return the
header.payload.signature string ready to send. Implementing generation
by hand is strongly discouraged: cryptography has too many pitfalls (non-constant
comparisons, incorrect handling of alg: none, etc.).
Does the decoder accept an expired JWT?
Yes. The decoder simply displays the token's content without judging its
temporal validity. It evaluates neither exp, nor nbf, nor the signature.
It is useful to understand why a token has been rejected by an API: you can
compare the value of exp to the current time to confirm that it is indeed
expired.
Is my JWT valid if the decoder displays it correctly?
No. Display only proves that the string is well-formed (three segments separated by dots, correct Base64URL encoding, valid JSON in the header and payload). That says nothing about the token's authenticity. A fully forged JWT can display without error in a decoder, which is precisely why it must be passed to a verifier.
Example request
curl -X POST https://cdrn.fr/api/v1/tools/jwt-decoder/execute \
-H "Content-Type: application/json" \
-d '{"token":"..."}'
Input schema
| Field | Type | Required | Default |
|---|---|---|---|
token |
text | ✓ | – |
Endpoints
GET https://cdrn.fr/api/v1/tools- lists every available toolGET https://cdrn.fr/api/v1/tools/jwt-decoder- returns the schema for this toolPOST https://cdrn.fr/api/v1/tools/jwt-decoder/execute- runs this tool with a JSON payload