JWT Payload Best Practices — What to Put (and Not Put) in a Token
The payload of a JWT is only base64-encoded, not encrypted — anyone who holds the token can read every claim. Design the payload around that fact.
What belongs in a JWT
Keep it to what the server needs to authorize a request without a database lookup:
{
"sub": "user_8f14e45f",
"iss": "https://auth.example.com",
"aud": "https://api.example.com",
"exp": 1783468800,
"iat": 1783382400,
"roles": ["editor"]
}
sub— a stable user identifier (an ID, not an email).issandaud— who issued the token and who it's for, so a token minted for one API can't be replayed against another.expandiat— expiry and issue time. Always setexp; short-lived tokens limit the damage of a leak (see JWT expiration and refresh tokens).- Coarse authorization data — roles or a tenant ID, if your API checks them on every request.
The standard claim names are covered in detail in what are JWT claims.
What must never go in
Treat the payload as public. Never include:
- Passwords, password hashes, or security answers
- API keys, database credentials, or other secrets
- Sensitive personal data — government IDs, health data, full card numbers
Base64 is an encoding, not encryption. Decoding a token takes one line of code and no key. If you genuinely need confidential claims, that's what JWE (encrypted JWTs) is for — a signed JWS, which is what most people mean by "JWT", hides nothing. More on that in are JWTs encrypted?.
Keep it small
The token rides along on every request, usually in a header. Bloated payloads cost bandwidth and can exceed header size limits (commonly 8 KB) once you stack a few cookies alongside.
- Store permissions as a compact role (
"admin"), not a list of 40 permission strings. - Don't embed profile data (name, avatar URL, preferences) — fetch it once from an API instead.
- If the payload keeps growing, that's a sign state belongs server-side, not in the token.
Don't trust it until you verify it
Reading a claim is safe; acting on one isn't — until you've checked the signature. A client can decode and display exp, but the server must verify before honoring any claim, since anyone can forge an unverified payload. See how to verify a JWT signature.
Inspect your own tokens
The fastest way to audit what your app is actually putting in its tokens: paste one into the JWT decoder and read the payload — everything you see is what an attacker with the token sees. You can also generate test tokens with different claim sets while designing your schema.
Got a config file to check?
Open the config toolkit →