JWTJSON Web TokenAuthenticationAuthorizationWeb SecurityAPI SecurityBackend DevelopmentNode.jsOAuthCybersecurity

JWTs Explained: What's Actually Inside a Token (And What Isn't)

JWTs Explained: What's Actually Inside a Token (And What Isn't)

If you've ever worked with authentication in a web application, you've almost certainly encountered JWT (JSON Web Token). It's used by countless APIs, mobile apps, and modern authentication systems.

But despite its popularity, there's a surprising amount of confusion around what a JWT actually contains.

Many developers assume a JWT is encrypted. Others believe it's a secure place to store passwords or sensitive user information. Some even think it's impossible to modify.

None of those are true.

In this article, we'll break down exactly what's inside a JWT, what isn't, how it works behind the scenes, and the security mistakes developers should avoid.


What Is a JWT?

A JSON Web Token (JWT) is a compact, URL-safe string used to securely transmit claims between two parties.

Instead of storing session data on the server, the server issues a signed token containing information about the authenticated user. The client stores this token and sends it back with future requests.

A typical JWT looks like this:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
.
eyJ1c2VySWQiOjEyMywicm9sZSI6ImFkbWluIiwiZXhwIjoxNzM1Njg5NjAwfQ
.
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

Notice the two dots (.). They separate the token into three distinct parts.


The Three Parts of a JWT

Every JWT contains:

Header.Payload.Signature

Each section is Base64URL encoded.

Let's explore each one.


Part 1: Header

The header contains metadata describing the token.

Example:

{
  "alg": "HS256",
  "typ": "JWT"
}

Typical fields include:

This information tells the server how the token was signed.

After Base64URL encoding, it becomes something like:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9

This isn't encrypted—it is simply encoded.


Part 2: Payload

The payload contains claims.

Claims are pieces of information about the user or authentication event.

Example:

{
  "sub": "123456789",
  "name": "Alice",
  "role": "admin",
  "iat": 1735600000,
  "exp": 1735603600
}

Common JWT claims include:

Claim Meaning
sub Subject (usually user ID)
iss Issuer
aud Audience
iat Issued At
exp Expiration Time
nbf Not Before
jti Token Identifier

Applications can also include custom claims:

{
  "userId": 42,
  "plan": "premium",
  "role": "editor"
}

Again, this section is encoded, not encrypted.

Anyone who has the token can decode it in seconds.


Part 3: Signature

The signature is what gives JWTs their integrity.

The server computes something like:

HMACSHA256(
    Base64Url(header) + "." + Base64Url(payload),
    SECRET_KEY
)

The result becomes the third section of the token.

The server later recomputes this signature to verify:

If even a single character in the payload changes, the signature becomes invalid.

To experiment with cryptographic digests and see how SHA-256 or HMAC signatures behave when input data changes, try our interactive Hash Generator:

Hash Generator (MD5 / SHA1 / SHA256)

Is JWT Encrypted?

This is the biggest misconception.

Standard JWTs are not encrypted.

They're only:

Encoding is not encryption.

For example:

eyJuYW1lIjoiQWxpY2UifQ

can easily be decoded back into:

{
  "name": "Alice"
}

This means anyone holding the token can read its contents.

If you want to quickly encode text or decode Base64 strings to verify how easily raw data is read, test it right in your browser using our Base64 Encoder / Decoder:

Base64 Encoder / Decoder

What Should NEVER Be Stored Inside a JWT?

Since JWT payloads are readable, never store:

❌ Passwords

❌ API keys

❌ Database connection strings

❌ Credit card information

❌ OTPs

❌ Secret tokens

❌ Refresh token secrets

❌ Personal information you wouldn't want exposed

A JWT should contain only information that is safe to expose if someone inspects the token.


What SHOULD Be Stored?

JWTs work best when storing lightweight identity information.

Good examples include:

Keep the payload as small as possible.

Large JWTs increase request size because the token is sent with every authenticated API call.


Can Someone Modify a JWT?

Yes.

Anyone can modify:

Because they're just Base64URL-encoded text.

However, after modification, the signature becomes invalid.

For example:

Original payload:

{
  "role": "user"
}

Modified payload:

{
  "role": "admin"
}

The attacker can create the modified token—but cannot generate a valid signature without the server's secret key (or private key, depending on the signing algorithm).

The server immediately rejects it.


How JWT Verification Works

When a request arrives:

  1. The client sends the JWT.

  2. The server splits it into three parts.

  3. The server recomputes the signature.

  4. The signatures are compared.

  5. The expiration time is checked.

  6. The issuer and audience are validated (if configured).

  7. If everything matches, the request is authenticated.

If any check fails, access is denied.


JWT Does NOT Store Session State

Traditional authentication works like this:

Browser
    ↓
Session ID
    ↓
Server Session Store

The server remembers each logged-in user.

JWT authentication usually works differently:

Browser
    ↓
JWT
    ↓
Server verifies signature

No database lookup is required just to identify the user.

This makes JWTs ideal for:


Common JWT Myths

Myth 1: JWT Is Encrypted

False.

It is encoded and signed.


Myth 2: JWT Cannot Be Read

False.

Anyone can decode the payload.


Myth 3: JWT Prevents Tampering Automatically

Partially true.

JWT detects tampering using the signature, but only if the server verifies it correctly.


Myth 4: Bigger JWT Means More Secure

False.

Large JWTs only increase bandwidth usage.


Myth 5: JWT Never Expires

False.

Well-designed JWTs include the exp claim and should have relatively short lifetimes.


Best Practices for Using JWTs


Decode a JWT Yourself

If you're curious about what a token contains, you can decode the first two sections manually.

The header and payload are simply Base64URL-encoded JSON. Instead of decoding each Base64 segment separately, you can paste any full JWT directly into our client-side JWT Decoder to instantly inspect its claims, header metadata, and expiration status right in your browser with 100% privacy:

JWT Decoder

You can also use our Base64 Encoder / Decoder if you want to inspect individual raw Base64 segments, or our Hash Generator to understand how cryptographic hashes and HMAC digests work alongside signing algorithms.

Remember: decoding a JWT does not verify its authenticity. Only the signature verification process using the correct secret or public key can prove that a token hasn't been altered.


Final Thoughts

JWTs are one of the most widely used authentication mechanisms in modern applications, but they're often misunderstood.

The key takeaway is simple:

A JWT is not encrypted, not secret, and not a secure place to store sensitive information. Its real strength lies in allowing servers to verify authenticity without maintaining session state, making it an efficient and scalable choice for APIs and distributed systems.

Once you understand what each part does—and, just as importantly, what it doesn't—you'll be able to design more secure authentication systems and avoid many of the common pitfalls developers encounter when working with JWTs.