A developer opens browser dev tools, checks the network tab, and sees a login token that looks like a long block of random text. It has dots in the middle, it sits beside an Authorization header, and it clearly matters because the app stops working when the token is missing. The natural question is: what is actually inside it?
Many modern apps use JSON Web Tokens, usually called JWTs, to carry login or authorization information between systems. BlinkCalc's JWT Decoder can split a token into readable parts so you can inspect the header and payload. That is useful for debugging, but it comes with an important warning: decoding a JWT is not the same as proving that the token is trustworthy.
Educational note: do not paste sensitive production tokens into tools unless you understand the privacy and security implications. Use fake, expired, or redacted tokens for learning whenever possible.
What a JWT is
A JWT is a compact string that contains JSON data. It is often used by web apps, APIs, identity providers, and mobile apps to pass claims about a user, a session, or an authorization event.
A typical JWT has three parts separated by dots:
header.payload.signature
The header and payload are Base64URL-encoded JSON. The signature is created from the first two parts plus a secret or private key, depending on the signing algorithm. A server can verify the signature to check whether the token was issued by a trusted party and has not been changed.
JWTs are popular because they are portable and self-contained. A service can read claims such as user id, issuer, audience, and expiry without calling a session database for every request. That convenience also means tokens should be designed carefully, kept short-lived where appropriate, and treated as sensitive.
The header
The header describes how the token is signed. A safe fake header might look like this:
{
"alg": "HS256",
"typ": "JWT"
}
The typ value usually says JWT. The alg value names the signing algorithm. Common examples include HS256 for an HMAC-based signature and RS256 for an RSA-based signature.
The header is not a place to put user information. It is metadata about the token format and signing method. When debugging, the header can tell you whether the app is using the expected algorithm, but verification belongs on the server or in trusted code with the correct key material.
The payload
The payload is where claims live. Claims are statements about the token subject or the token itself. A fake decoded payload might look like this:
{
"sub": "user_7429",
"name": "Avery Chen",
"iss": "https://login.example.test",
"aud": "blinkcalc-demo-api",
"iat": 1780473600,
"exp": 1780477200,
"role": "editor"
}
This is readable JSON after decoding. It is not automatically secret. If a claim is sensitive, it usually should not be placed in a normal signed JWT payload. Signed JWTs are commonly visible to the client that holds them.
Payloads should stay focused. User id, issuer, audience, issue time, expiry, and a small number of authorization hints may be appropriate. Large profile objects, private notes, API keys, and personal records are poor candidates.
The signature
The signature protects integrity. It helps the receiver detect whether the header or payload has been modified. For example, a user should not be able to change "role": "viewer" to "role": "admin" and have the API accept it.
The signature is calculated from the encoded header, encoded payload, and signing key. With symmetric algorithms such as HS256, the same secret is used to sign and verify. With asymmetric algorithms such as RS256, a private key signs and a public key verifies.
A decoder can show the signature segment as text, but it cannot prove trust unless it verifies the signature with the correct secret or public key and checks the claims. That is why decoding is a reading step, not a security decision.
Common claims
JWTs use registered claim names for common ideas. You do not need every claim in every token, but these appear often:
| Claim | Meaning | Typical use |
|---|---|---|
sub | Subject | User id or account id |
exp | Expiration time | When the token should stop being accepted |
iat | Issued at | When the token was created |
iss | Issuer | System that issued the token |
aud | Audience | Intended recipient or API |
nbf | Not before | Earliest time the token should be accepted |
jti | JWT id | Unique token identifier |
Claims are only as useful as the validation around them. An API should check expiry, issuer, audience, signature, and any authorization claims it uses for access decisions. Reading a claim in the browser can explain behavior, but it should not become a client-side trust boundary.
Why JWTs look encrypted
JWTs often look encrypted because Base64URL text is dense and unfamiliar. In most everyday JWTs, the header and payload are encoded, not encrypted. Encoding changes representation. Encryption hides meaning from people who lack the key. Those are different protections.
If you paste the first two JWT segments into a decoder, you can usually read the JSON. Anyone holding the token can do the same. That is why normal JWT payloads should not contain passwords, secrets, private keys, payment details, or sensitive personal data.
Encrypted JWTs do exist, often called JWEs, but they are a different structure. Many login tokens seen in frontend apps are signed JWTs rather than encrypted tokens.
Base64URL encoding
Base64URL is a URL-safe variant of Base64. Standard Base64 can use characters such as +, /, and =. Base64URL swaps some characters so the result is easier to use in URLs, headers, and cookies.
That explains why JWT segments are readable after decoding but do not look like ordinary JSON at first glance. If you are learning the format, the Base64 Encoder and Decoder can help you understand the general idea of encoding. JWTs use Base64URL specifically, so small character differences matter.
The dots are separators. They are not part of the JSON. If a JWT has fewer or more than three parts, it may be malformed, a different token type, or copied incorrectly.
Decoding does not verify authenticity
This is the most important distinction. Decoding answers: "What does this token say?" Verification answers: "Can I trust that it was issued by the expected party and has not been changed?"
A malicious person can create a token-shaped string with any payload they like. It may decode beautifully. Without a valid signature from the trusted issuer, it should not be accepted. A token can also have a valid signature and still be rejected because it is expired, issued for a different audience, or missing required claims.
For production systems, use well-maintained libraries and follow your identity provider's documentation. Do not write your own verification logic from scratch unless you have a strong reason and security expertise.
Expiry and time checks
The exp, iat, and nbf claims are usually Unix timestamps. They count seconds since 1970-01-01 00:00:00 UTC. If a token expires at 1780477200, a decoder can show the number, but a timestamp converter is often easier for humans.
Expired tokens should generally stop being accepted. A small clock skew allowance may exist because servers can differ by a few seconds, but long allowances weaken the point of expiry. Short-lived access tokens are often paired with refresh tokens, session rotation, or reauthentication flows.
When a token seems to "randomly" fail, check the current time, server time, expiry, audience, and issuer. Time zone confusion can make a valid-looking timestamp feel wrong even when the numeric value is correct.
A safe fake token structure
For learning, avoid real tokens. A fake token can show the shape:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJzdWIiOiJ1c2VyXzc0MjkiLCJpc3MiOiJodHRwczovL2xvZ2luLmV4YW1wbGUudGVzdCIsImF1ZCI6ImRlbW8tYXBpIiwiZXhwIjoxNzgwNDc3MjAwfQ.
fake-signature-for-documentation-only
A real JWT signature segment would be produced by signing the encoded header and payload. The example above is intentionally not a valid production credential. It is enough for explaining why the header and payload can be decoded into JSON-like data.
After decoding a payload, the JSON Formatter can make nested claims easier to read. Some identity providers add arrays, permission objects, tenant ids, or scope strings. Formatting helps separate structure from meaning.
How to use the JWT Decoder
Open the JWT Decoder, paste a token into the input, and inspect the decoded header and payload. Check whether the token has three segments. Look for expected claims such as issuer, audience, subject, issue time, and expiry.
Use the result as a debugging aid. If a frontend shows the wrong role, the payload may explain what the client received. If an API rejects a request, the payload may reveal an expired token or wrong audience. The decoder helps you read the token, but server-side logs and verification errors tell the rest of the story.
Before pasting, remove secrets when possible. For screenshots or support tickets, redact the token and share only the decoded claim names and safe fake values.
When related tools help
Use the Base64 Encoder and Decoder when you want to understand encoding outside the JWT wrapper. It is useful for learning why encoded text is not automatically encrypted.
Use the JSON Formatter when a decoded payload contains nested objects or arrays. Pretty formatting makes claims easier to review and compare.
Use the Hash Generator to learn about one-way hashes and message digests. Hashing, signing, encoding, and encryption are separate ideas, and seeing them side by side helps prevent security vocabulary from blurring together.
Debugging an API request with a JWT
When an API request fails, the token is only one possible cause. A practical debugging pass starts with the status code. A 401 often points to missing or invalid authentication. A 403 often means the user is authenticated but not allowed to perform the action. Those meanings can vary by API, but the distinction is useful.
Next, decode a safe copy of the token and check the obvious claims. Is exp in the past? Does aud match the API? Does iss match the identity provider you expected? Is the sub the user you are testing with? If the payload contains scopes, do they include the operation being attempted?
Then compare the request itself. Is the Authorization header shaped as Bearer <token>? Did a proxy strip the header? Is the frontend accidentally sending an old token from storage after refresh? Many token bugs are lifecycle bugs rather than token-format bugs.
Storage and handling basics
Token storage is a security design decision. Some apps use HTTP-only cookies. Some use memory. Some use browser storage. Each choice has tradeoffs around cross-site scripting, cross-site request forgery, refresh behavior, and developer ergonomics. Follow the guidance for your framework and identity provider.
Avoid logging full tokens. Server logs, browser console output, analytics events, support screenshots, and error tracking tools can all become accidental token stores. If you need to debug, log a short token id, expiry, issuer, or redacted prefix rather than the complete credential.
JWTs are convenient because services can inspect them quickly. That same convenience means leaked tokens may be useful to an attacker until they expire or are revoked. Treat them like temporary credentials, not harmless strings.
Common mistakes
One mistake is assuming a readable payload means the token is unsafe. Readability alone is normal for signed JWTs. The unsafe part is placing sensitive secrets in the payload.
Another mistake is trusting decoded claims in frontend code. A browser can read a role claim, but authorization must be enforced by the server or trusted backend layer.
A third mistake is ignoring aud and iss. A token issued for one API should not automatically be accepted by another. Audience and issuer checks reduce token confusion between systems.
A fourth mistake is treating expiry as a user interface detail. Expiry is a security control and should be checked where access is granted.
A fifth mistake is using old examples from the web without checking current library guidance. JWT libraries and identity providers have changed defaults over time, especially around algorithm handling.
FAQ
Is a JWT encrypted?
Usually no. Many JWTs are signed but not encrypted. The payload can often be decoded by anyone who has the token. Encrypted JWTs exist, but they use a different structure and should not be assumed.
What are JWT claims?
Claims are fields inside the payload that state something about the token, user, issuer, audience, time, or permissions. Common examples include sub, exp, iat, iss, and aud.
Does decoding a JWT prove it is valid?
No. Decoding only reveals the contents. Validity requires signature verification, claim checks, expiry checks, issuer checks, and audience checks using trusted code and keys.
What does exp mean in a JWT?
exp is the expiration time. It is usually a Unix timestamp in seconds. After that time, a properly validating system should reject the token, subject to any configured clock skew allowance.
Can I paste a real JWT into an online decoder?
Avoid pasting sensitive production tokens unless you fully understand the tool and the environment. Use fake, expired, or redacted tokens for learning and support examples.
Why does a JWT have three parts?
The three parts are the encoded header, encoded payload, and signature. The dots separate them so software can decode the first two parts and verify the third.