A JWT (JSON Web Token) is a token format for exchanging information (claims) expressed as JSON in a way that lets tampering be detected. It has a three-part structure, header.payload.signature, where each part is base64url-encoded and joined with periods (.). JWTs are widely used for stateless authentication, where the server holds no session, and for API authorization. This article lays out, accurately, the structure of a JWT, the contents of each part, signatures, the crucial point that the payload is not encrypted, the use cases, and the security pitfalls.
1. What a JWT is — three parts and base64url
A JWT is a compact token format for safely exchanging claims (assertions or pieces of information) expressed as JSON. The most common form is the signed form (a JWS), which consists of the following three parts.
- header: metadata indicating the token type and the signing algorithm.
- payload: the claims you actually want to convey (who it is for, until when it is valid, and so on).
- signature: a signature over the header and payload, used to detect tampering.
Each of these three parts is base64url-encoded (a URL-safe variant of Base64) and the parts are joined with periods (.). In other words, the whole thing has this form.
base64url(header).base64url(payload).base64url(signature)
An actual token, then, is a string split into three parts, for example like this.
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0Iiwicm9sZSI6ImFkbWluIn0.abc123signature
+ becomes -, / becomes _, and the trailing = padding is dropped. This makes it safe to embed directly in URLs and headers. For base64url, see also our Base64 explainer.
2. The contents of each part — header fields and registered claims
The header and the payload are both just plain JSON objects once decoded. Let us look at their contents in turn.
The header
The header mainly carries two fields.
alg: the algorithm used for the signature (e.g.HS256,RS256,ES256).typ: the token type. UsuallyJWT.
Example: { "alg": "HS256", "typ": "JWT" }
The payload and registered claims
You can put arbitrary claims in the payload, but there are several registered claims whose meaning is defined by the specification. For interoperability, use these with their defined names and meanings.
| Claim | Meaning | Notes |
|---|---|---|
iss | Issuer | The principal that issued the token |
sub | Subject | What the token is about (e.g. a user ID) |
aud | Audience | The intended recipient(s) of the token |
exp | Expiration | Invalid from this time on. UNIX seconds |
nbf | Not before | Invalid before this time. UNIX seconds |
iat | Issued at | The time the token was issued. UNIX seconds |
Example: { "sub": "1234", "role": "admin", "iss": "https://auth.example.com", "exp": 1924905600 }
In this way, the payload carries the information needed for authorization: who it is (sub), what privileges they have (custom claims such as role), and until when it is valid (exp).
3. Signatures — HMAC (shared key) and RSA/ECDSA (public key)
The signature is the heart of a JWT. It is computed over the base64url-joined header and payload string and attached as the third part. There are broadly two families of signing scheme.
HMAC (such as HS256) — shared key
HMAC is a scheme where the issuer and the verifier hold the same secret key (a shared key). HS256 refers to HMAC using SHA-256. Because both the signer and the verifier need to know the same key, it suits cases where issuing and verifying happen within the same trust boundary (the same service).
RSA/ECDSA (such as RS256, ES256) — public key
RSA and ECDSA use public-key cryptography. The issuer signs with a private key, and the verifier checks it with the corresponding public key. Since you do not have to hand the private key to the verifier, this suits cases where the issuer and verifier differ (e.g. an auth server issues tokens and multiple APIs verify them with the public key).
| Aspect | HMAC (HS256) | RSA / ECDSA (RS256, ES256) |
|---|---|---|
| Key type | Shared key (a single secret key) | A private + public key pair |
| Who signs | Whoever holds the shared key | The issuer holding the private key |
| Who verifies | Whoever holds the same shared key | Anyone holding the public key |
| Suited configuration | Issuing and verifying in the same service | Issuer and verifier are separate |
4. The payload is not encrypted — keep secrets out
This is the most commonly misunderstood point about JWTs. The payload of a standard JWT (a JWS) is not encrypted. base64url is merely an encoding, so anyone can decode it and read its contents without any key.
Therefore, you must not put confidential information like the following in the payload.
- Passwords or fragments of them.
- Payment information such as credit card numbers.
- Personal or internal information that would be harmful if leaked.
If you need to hide the contents themselves, you have to use JWE (JSON Web Encryption), which encrypts the payload, rather than a signature-only JWS. Always keep in mind that the "JWT" used in most situations is a JWS and is not encrypted.
5. Use cases — stateless authentication and API authorization
The greatest advantage of a JWT is that the token itself carries the information it needs (it is self-contained). This lets authentication and authorization work without the server holding any session.
- Stateless authentication: after login, the server issues a JWT, and the client sends it on subsequent requests. The server can identify the user merely by verifying the signature, without consulting a session store.
- API authorization: privileges (such as
roleor scopes) are placed in the token, and an API uses them to decide whether to allow access. Even across microservices, each service can authorize independently if it verifies the token with the public key. - Inter-service and third-party integration: in OAuth 2.0 / OpenID Connect, JWTs are often used to represent access tokens and ID tokens, so that the issuer signs and the recipient verifies with the public key, passing information safely.
exp) plus a separately provided refresh-token or revocation-list mechanism.
6. Security pitfalls — alg=none, expiration, storage location
Used correctly, JWTs are powerful, but a flawed implementation can break authentication entirely. Here are the main points to watch.
- The
alg=noneattack: a classic attack where the header'salgis rewritten tononeand the signature is left empty, getting a token accepted as "no signature verification needed." On the verifying side, fix the set of allowed algorithms and always rejectnoneand any unexpectedalg. Beware also of attackers switching the header'salgto confuse the verification logic (for example, making RS256 be mistaken for HS256 so a public key is treated as a shared key). - Always verify the expiration: on the verifying side, check
exp(andnbf/iatas needed) and reject expired tokens. Set the expiration short to minimize the damage if a token leaks. - Storage location: when holding a token in the browser,
localStoragecan be read via XSS. Depending on the use case, consider a Cookie with theHttpOnlyattribute, and also apply CSRF protection. In any case, the connection must be HTTPS. - Always verify the signature: obviously, you must not skip signature verification or swallow verification errors. Verify
audandissas well, and accept only tokens addressed to you and from a trusted issuer.
Frequently Asked Questions (FAQ)
What is a JWT?
A JWT (JSON Web Token) is a token format for exchanging claims (information) expressed as JSON in a way that lets tampering be detected. It has a three-part structure of header, payload, and signature; each part is base64url-encoded and the parts are joined with periods (.). JWTs are widely used for stateless authentication, where the server keeps no session state, and for passing authorization information to APIs.
Is the payload of a JWT encrypted?
No. The payload of a standard JWT (a JWS) is not encrypted; it is merely base64url-encoded. Anyone can decode it and read its contents without any key. The signature exists to detect tampering, not to keep the contents secret. Therefore you must not put confidential information such as passwords or credit card numbers in the payload. If you need to hide the contents themselves, you have to use JWE, which encrypts the payload.
What is the role of a JWT signature?
The signature is used to verify that a token was created by a legitimate issuer and has not been tampered with along the way. With HMAC (such as HS256), the issuer and verifier share the same secret key; with RSA or ECDSA (such as RS256 or ES256), the issuer signs with a private key and the verifier checks it with the corresponding public key. A token whose signature does not match is rejected as invalid. The signature guarantees integrity and authenticity, but it does not encrypt or hide the contents of the payload.