Signed, encrypted, or both? Choosing what a JWT should be

The JOSE family gives you two operations that people routinely confuse. Signing proves origin and integrity: anyone can read the payload, nobody can alter it unnoticed. Encrypting hides the payload: only the recipient can read it, and on its own it says nothing about who produced it.

The mistake that keeps coming back

A signed JWT is not confidential. Its payload is base64url, not encryption. Anyone holding the token reads it, including the browser it passed through and the log file it landed in.

So the rule is simple: if the claims must not be read by the bearer, a JWS is the wrong tool, whatever the algorithm.

A decision, in three questions

  • Does the recipient need to know who issued it? Then sign.
  • Would it be a problem if the bearer read the claims? Then encrypt.
  • Both? Then sign first, encrypt the result. That is a nested token.

The order matters. Signing an encrypted blob proves who encrypted it, not who wrote the claims. Encrypting a signature proves who wrote the claims and hides them at once, which is almost always what people mean.

The cost you are choosing

A nested token is bigger, slower to produce and slower to verify, and it needs two sets of keys with two rotation schedules. That is a real operational cost. Pay it when the confidentiality requirement is real, not because it sounds more secure.

And there is a cheaper option people forget: put an opaque identifier in a signed token and keep the sensitive part on the server. No encryption to manage, and the claims never leave your side at all.

JWT-Framework implements all three shapes, with a dedicated class for nested tokens.