I work in fintech, and the gap between what developers assume JWT does and what it actually does has caused real damage — leaked user data, privacy issues, compliance headaches.

JWT is a container, not a lock

JWT is a format.

Three base64-encoded parts:

  • header
  • payload
  • optional signature

Separated by dots.

That's it.

It gives structure to data in transit. It does not hide anything.

Anyone holding a JWT can decode the payload in seconds without any key.

It looks cryptographic — which is exactly why people trust it more than they should.

Three flavors, and most people only know one

Unsigned JWT (alg: none) No signature, no integrity check. The spec allows it. Your server shouldn't.

JWS (signed) What nearly everyone actually means when they say "JWT".

  • The payload is fully readable
  • The signature proves it hasn't been tampered with

Think:

Tamper-proof envelope, clear plastic

JWE (encrypted) The only variant that actually hides the payload.

Less common, but the only one that provides real confidentiality.

How JWE works under the hood

JWE uses hybrid encryption:

  • A random content encryption key (CEK) encrypts the payload (fast, symmetric — e.g. AES)
  • The CEK itself is encrypted using the receiver's public key
  • Both are included in the token

Only the holder of the private key can:

  1. Decrypt the CEK
  2. Use it to decrypt the payload

The frontend question nobody asks early enough

If JWE is encrypted… how does the frontend use it?

Short answer:

It doesn't read it.

Typical flow:

  • Backend creates the JWE
  • Frontend stores it (memory / cookie / storage)
  • Frontend sends it back on requests
  • Backend decrypts it

The frontend treats it as an opaque blob.

Why the frontend should not decrypt JWE

Decryption requires a private key.

If that key exists in frontend code:

  • It can be extracted
  • The encryption becomes meaningless

Browsers are not secure environments:

  • extensions
  • dev tools
  • network proxies

Everything shipped to the client can be inspected.

Where I keep seeing this go wrong

The pattern repeats:

Teams adopt signed JWTs… then start putting sensitive data inside:

  • emails
  • internal IDs
  • roles
  • permissions

Because it "looks secure".

It isn't.

Every system touching that token can read it:

  • browser storage
  • logs
  • middleware
  • proxies

In fintech, that's not just bad design — it becomes a GDPR / PSD2 issue.

The rule I stick to

If the data needs to stay secret, it doesn't go in a signed JWT.

Either:

  • use JWE (decrypt server-side only)
  • or don't put it in the token at all

Quick mental model

  • JWT → format
  • JWS → trust the data hasn't changed
  • JWE → hide the data

Final thought

JWT is a good tool. I use it daily.

But:

encoded ≠ encrypted signed ≠ secret

Treating a transparent envelope like a vault is how sensitive data ends up where it shouldn't be.

Written by The Fintech Engineer Breaking down how money really works in the modern world.