JWT Structure
A JSON Web Token is three Base64url segments joined by dots: a header naming the signature algorithm, a payload carrying claims about who you are and until when, and a cryptographic signature over the first two. Defined in RFC 7519, the structure is inspectable by anyone — the signature protects integrity, not secrecy.
O guia abaixo está disponível apenas em inglês.
JWT Structure explained
When a service wants to hand you proof of login that any of its servers can check without a shared session store, it hands you a JWT. The token is a compact, URL-safe string — you have seen them: three chunks of apparent gibberish separated by two dots, riding in an Authorization header or a cookie. The gibberish is not encryption; it is Base64url, and it decodes in one line of code.
The format descends from a family of specifications: RFC 7519 defines the token itself, RFC 7515 (JWS) defines how the signature wraps it, and the JOSE working group supplied the registered claim names and algorithm identifiers. That lineage explains the format's most misunderstood property, covered plainly below — signed means tamper-evident, not secret.
This guide decodes a real token segment by segment, lists the registered claims with their exact semantics, compares the two signature families you will meet — HS256 and RS256 — and states the rules that keep tokens safe, including why verification belongs on the server, with the issuer's key, on every request.
Everything below you can do to a real token in seconds — the JWT Decoder splits and decodes all three segments locally, flagging timestamps as it goes.
Because every segment is Base64url, the Base64 guide is the companion read: it explains the alphabet, the dropped padding and why tokens are URL-safe.
Three segments, two dots
The compact serialization is header.payload.signature — each segment independently Base64url-encoded, the dots as literal separators. The encoding is deliberately unpadded, so a token contains only letters, digits, hyphens and underscores: safe in URLs, headers and cookies without escaping. Decoding the first two segments is not a hack — it is the intended way to inspect a token; the third segment is where verification happens.
A real token, with a signature computed over it, decodes exactly like this:
A token with a valid HS256 signature
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL2F1dGguZXhhbXBsZS5jb20iLCJzdWIiOiJ1c2VyXzg0OTIiLCJhdWQiOiJhcGkuZXhhbXBsZS5jb20iLCJpYXQiOjE3NjcyMjU2MDAsImV4cCI6MTc2NzMxMjAwMCwianRpIjoiYjBmNmMyZDQtNGU3YS00YzFmLTlhMmItM2Q1ZTdmOWExYzNlIn0.iDPqw4BRxZtM064Y3EH83XLB0cgEjbj5snSXeM846VY
The first two segments, decoded
{"alg":"HS256","typ":"JWT"}
{"iss":"https://auth.example.com","sub":"user_8492",
"aud":"api.example.com","iat":1767225600,
"exp":1767312000,
"jti":"b0f6c2d4-4e7a-4c1f-9a2b-3d5e7f9a1c3e"}The header: the token's table of contents
The header is a small JSON object — formally the JWS Protected Header. Two fields do almost all the work: alg names the signing algorithm, and typ records the media type, conventionally JWT. A third, kid (key ID), points the verifier at the right key when an issuer publishes several. The header is signed but never encrypted, and it is trusted only after the signature verifies — until then, alg is a claim, not a fact.
| Field | Meaning | Example |
|---|---|---|
| alg | Signature algorithm — the verifier's first routing decision | HS256, RS256, ES256 |
| typ | Media type; JWT by convention, ignored by most libraries | JWT |
| kid | Which key to verify with, when several are published | 2026-01-signing |
| none | The pseudo-algorithm meaning 'unsigned' — reject unless truly requested | (a known attack target) |
The payload: registered claims and what each promises
The payload is a JSON object of claims. Seven are registered by RFC 7519 with precise, interoperable meanings; everything else is private to the issuer and the audience. Times are NumericDate values — seconds since the Unix epoch, not milliseconds — and the time claims are advisory to the verifier: checking them is the verifier's job, not something the format enforces.
| Claim | Full name | What it asserts |
|---|---|---|
| iss | Issuer | Who created and signed the token — a URL or name |
| sub | Subject | Whom the token is about — a user or client identifier |
| aud | Audience | Which recipients the token is for; verifiers reject it if they are not listed |
| exp | Expiration | Seconds-since-epoch deadline; invalid once passed |
| nbf | Not before | Earliest time the token may be accepted |
| iat | Issued at | When the token was created — evidence of age, not an expiry |
| jti | JWT ID | A unique identifier for this token — the hook for revocation lists |
The signature: HS256, RS256 and how verification works
The signature is computed over the signing input — the encoded header, a dot, the encoded payload — using the algorithm the header names. HS256 is HMAC-SHA256 with a shared secret: fast and symmetric, appropriate only when the signer and every verifier form one trust domain, because anyone holding the secret can mint tokens. RS256 is RSA: the issuer signs with a private key and anyone — including a browser — can verify with the published public key, which is what makes it the default for federated protocols like OAuth 2.0 and OpenID Connect.
Verification recomputes the signature and compares. That is the entire mechanism — and it is why the alg header alone decides how the check runs. Libraries hardened themselves after the algorithm-confusion attacks of the early 2010s: a token claiming alg none, or an RS256 token replayed as HS256 using the public key as the HMAC secret, verifies only against verifiers that fail to pin their expected algorithm.
The two families at a glance
HS256: HMAC-SHA256(secret, header + '.' + payload)
signer and verifier share the secret
RS256: RSA-SHA256(private key, header + '.' + payload)
issuer signs; anyone verifies with the public keyThe rule that follows
Pin the expected algorithm per issuer. Never derive it solely from the token's own header. Never accept alg: none.
Signed, not sealed: what the signature does not do
The signature proves the token was issued by whoever holds the key and has not been altered since — integrity and authenticity. It provides zero confidentiality: Base64url is an encoding, and the payload is readable by anyone who sees the token, including browser extensions, proxies when tokens travel in URLs, and log collectors. The standing rules follow: never put secrets in a JWT payload, never send tokens in URLs, and treat every decoded claim as data rather than as a decision.
That last point is the client-side trap. A browser can decode a token and read exp or sub — but it cannot meaningfully verify the token, because it does not hold the issuer's key: with HS256 the secret must never reach the browser at all, and with RS256 a client-side check proves nothing about what the holder may access. Clients may inspect tokens for presentation — showing a name, warning about expiry — but the server must verify the signature and every claim on every request. Inspection is not verification, and readable is not authorised.
Inspecting tokens safely — the practical loop
A disciplined inspection loop takes seconds: decode the header and payload, check exp and nbf against the clock, confirm iss and aud are what you expect, and only then — on the server — verify the signature with a pinned algorithm and the right key. Everything except the final verification is pure text processing, which is why a decoder that runs entirely in your browser is the right tool: real tokens are bearer credentials, and credentials belong in tabs you control, not in websites that might forward them.
Remember what the structure cannot give you: revocation — jti-based blocklists must be built and checked server-side; confidentiality — use JWE if you need encrypted tokens; and trust — a structurally perfect token from an issuer you never configured is worthless. The structure tells you what was promised; only verification tells you the promise is intact.
Frequently asked questions
Is it safe to paste my real token into a JWT decoder?
It is here, because the decoder on this site runs entirely in your browser: the token is never uploaded, no server could log it, and the site's Content-Security-Policy blocks outbound requests so the page cannot transmit even by accident. Be far more careful with arbitrary online decoders — a JWT is a bearer credential, and anyone who reads it can use it until it expires.
Does the signature encrypt the token's contents?
No — the signature only detects tampering. Base64url is a reversible encoding, not encryption: anyone holding the token can read every claim, which is why passwords and secrets must never go into the payload. Confidential variants exist as JWEs — encrypted JSON Web Tokens — but the tokens in ordinary Authorization headers are JWSs: signed, readable, tamper-evident.
What is the difference between HS256 and RS256?
The key model. HS256 is HMAC-SHA256 with one shared secret: every party that can verify tokens can also mint them, so it suits single services controlling both ends. RS256 is RSA: the issuer signs with a private key and verifiers check with a public key — verification never grants the power to forge. Federated identity standards build on RS256 for exactly that reason.
Why must JWTs be verified on the server?
Because verification needs the issuer's key and an authorisation decision, and only the server has both. With HS256 the shared secret must never reach a browser at all; with RS256 a browser could cryptographically check a signature, but its own conclusion proves nothing about access — clients can be modified. The server re-verifies the signature and checks iss, aud and exp on every request.
What happens when a JWT expires?
Nothing automatic — exp is a claim a verifier must check. A compliant server compares it against the current time and rejects the token once it passes; a sloppy one keeps accepting it forever. Refresh flows exist for this reason: short-lived access tokens checked on every request, plus a longer-lived refresh token the server can revoke when needed.
Can I trust a token whose signature I have not verified?
Only as an unauthenticated hint. An unverified token could have been written by anyone — its iss, sub and even its exp are just text until the signature check passes. The safe mental model: decoding tells you what the token claims; verification tells you who signed those claims and that they are unchanged. Never gate access on the former.
Which related tools should I use next?
- JWT DecoderDecode a JSON Web Token and see what every claim means.Open
- How Does Base64 WorkPlain-English guideOpen
- UUID VersionsPlain-English guideOpen
- What Is JSONPlain-English guideOpen
- JSON FormatterIndent, sort keys and strip comments with configurable output.Open
- JSON ValidatorValidate syntax with exact line and column, and repair it in one click.Open