A JWT, or JSON Web Token, is a compact string used to carry identity and claims between systems - most commonly to keep a user logged in after they sign in. At a glance it looks like one long jumble of characters, but it is really three separate pieces glued together with dots. This guide breaks a JWT into its three parts - the header, the payload and the signature - explains what each one holds, and makes one critical point clear: a JWT is encoded, not encrypted, so anyone can read the payload. You will also learn the difference between decoding a token and verifying it.
The three parts of a JWT
Every JWT has exactly three parts, separated by dots, in this order:
header.payload.signature
A real token looks like eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjMifQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c - three blocks split by two dots. Each of the first two blocks is a JSON object that has been Base64URL-encoded, and the third is the signature, also Base64URL-encoded. Base64URL is a URL-safe variant of Base64 that swaps a couple of characters so the token can travel safely in a URL or HTTP header. You can paste any token into the JWT Decoder to see the three parts split out and decoded for you.
The header
The first part is the header. It is a small JSON object that describes how the token was signed. Decoded, a typical header looks like this:
{ "alg": "HS256", "typ": "JWT" }
- alg is the signing algorithm. Common values are HS256 (HMAC with SHA-256, using a shared secret) and RS256 (RSA with SHA-256, using a private/public key pair).
- typ is the token type, almost always the literal string JWT.
The header tells the receiving system which algorithm to use when it checks the signature. It is purely descriptive metadata - it carries no user data and, like the payload, it is only encoded, never encrypted.
The payload and its claims
The second part is the payload, where the actual data lives. Each piece of data is called a claim. A decoded payload might look like this:
{ "sub": "1234567890", "name": "Ada Lovelace", "iat": 1718000000, "exp": 1718003600 }
Claims fall into two groups. Registered claims are standard, reserved names with agreed meanings:
- iss - the issuer, who created the token.
- sub - the subject, usually the user the token is about.
- aud - the audience, who the token is intended for.
- exp - the expiry time, after which the token is no longer valid.
- iat - the issued-at time, when the token was created.
- nbf - not-before, the earliest time the token may be used.
Importantly, exp, iat and nbf are numeric Unix timestamps - the number of seconds since 1 January 1970, not a human-readable date. A value like 1718003600 has to be converted to read it. Alongside these, you can add your own custom (private) claims such as name, role or email to carry whatever your application needs.
The signature
The third part is the signature, and it is what makes a JWT trustworthy. It is created by taking the encoded header and the encoded payload, joining them with a dot, and signing that string. In formula terms, the signed input is base64url(header) + "." + base64url(payload). How it is signed depends on the algorithm:
- For HMAC algorithms such as HS256, the input is signed with a shared secret. The same secret is used to sign and to verify.
- For RSA or ECDSA algorithms such as RS256, the input is signed with a private key, and anyone can verify it with the matching public key.
The signature provides integrity and authenticity: if anyone changes a single character of the header or payload, the signature no longer matches and verification fails, which proves the token has not been tampered with and that it came from a holder of the signing key. What the signature does not provide is confidentiality - it protects the token from being altered, not from being read.
Decoding is NOT verifying (and the payload is NOT encrypted)
This is the single most important thing to understand about JWTs, and the place most beginners go wrong. The payload is encoded, not encrypted. Base64URL is a reversible transformation that anyone can undo - it scrambles the text for safe transport, but it provides zero secrecy. That means anyone who holds the token can decode it and read every claim inside, no secret or key required.
Because of this, you must never put passwords, API keys, card numbers or any other secret in a JWT payload. Assume the contents are fully public to anyone who ever sees the token.
Decoding and verifying are two different actions:
- Decoding just reverses the Base64URL encoding to read the header and payload. It needs no key and tells you nothing about whether the token is genuine.
- Verifying recomputes the signature using the secret (for HMAC) or the public key (for RSA/ECDSA) and checks that it matches the signature in the token. Only verification proves a token is authentic and untampered.
A tool like the JWT Decoder decodes a token so you can read it - it does not, and cannot, prove the token is valid without the signing key. Your server is the place that must verify the signature before trusting any claim.
How to inspect a token safely
When you need to look inside a JWT - for example, while debugging why a login or API call failed - follow a few sensible habits:
- Use a decoder that runs in your browser and does not send the token anywhere. Treat any token as a live credential.
- Never paste a production access token into a random website. Anyone who captures it can act as that user until it expires.
- Check the exp claim first. Convert the Unix timestamp to a date and confirm the token has not already expired - an expired token is the most common cause of sudden authentication failures.
- Compare the alg in the header against what your server expects. A mismatch can point to a misconfigured or even malicious token.
- Remember that reading the payload is not proof of validity. Only your server, holding the signing key, can confirm the signature is genuine.
Where JWTs fit alongside encoding and hashing
It helps to place JWTs next to two related ideas. Base64URL, used throughout a JWT, is the same family of encoding used to move binary-safe text around the web - the guide on What Is Base64 Encoding? shows how that transformation works in both directions. Hashing is different: a hash is a one-way fingerprint that cannot be reversed, which is how passwords should be stored on a server rather than inside a token. You can experiment with one-way hashes using the Hash Generator. A JWT borrows from both - reversible encoding for the header and payload, and a cryptographic signature derived from a key for the third part.
Once you can see the three parts clearly, JWTs stop feeling mysterious. The fastest way to build that intuition is to paste a sample token into the JWT Decoder, read the header and payload side by side, and watch the claims - especially exp and iat - decode into something you can understand.
Frequently asked questions
- Is the payload of a JWT encrypted?
- No. The payload is only Base64URL-encoded, which is fully reversible, so anyone holding the token can decode and read every claim. Never store passwords or secrets in a JWT payload.
- What is the difference between decoding and verifying a JWT?
- Decoding just reverses the encoding to read the header and payload, and needs no key. Verifying recomputes the signature with the secret (HMAC) or public key (RSA/ECDSA) and checks it matches - only verifying proves the token is authentic and untampered.
- What are the three parts of a JWT?
- A JWT has three dot-separated parts: the header (which states the algorithm, such as HS256 or RS256), the payload (which holds the claims), and the signature (which proves integrity and authenticity). Each part is Base64URL-encoded.