pasetojwtsecuritytokenscryptographyauth

PASETO vs JWT: A Safer Token Format by Design

·8 min read·Security & Auth

The token format that removes the footguns

Most JWT vulnerabilities aren't flaws in the crypto — they're flaws in the *flexibility*. JWT lets the token declare its own algorithm, offers a none option, and supports a menu of algorithms of varying strength. That flexibility is exactly what alg: none and algorithm-confusion attacks exploit. PASETO (Platform-Agnostic SEcurity TOkens) takes the opposite stance: it bakes safe cryptographic choices into the format so the dangerous options simply don't exist.

If you're choosing a stateless token format in 2026, PASETO is the "secure by default" alternative worth knowing.

The core idea: versioned protocols, not free choice

A JWT header says "here's the algorithm, please use it." A PASETO token starts with a version and a purpose that together *determine* the cryptography — the token can't negotiate it. A PASETO looks like:

text
v4.public.<payload>.<footer>
v4.local.<payload>.<footer>
 │   │       │         │
 │   │       │         └─ optional footer (not encrypted, authenticated)
 │   │       └─ Base64url claims
 │   └─ purpose: "local" (encrypted) or "public" (signed)
 └─ version: v4 (the current recommended version)
  • version (v4) fixes the exact algorithms — there's no alg field to tamper with. Because the algorithm isn't attacker-controllable, alg: none and algorithm confusion are impossible by construction.
  • purpose is either:
  • - `local` — *symmetric encryption*. The claims are encrypted and authenticated with a shared secret key. Use when the same party issues and reads the token and the payload must be confidential.
  • - `public` — *asymmetric signature*. The claims are signed with a private key and verified with a public key (like RS256/ES256), but *not* encrypted. Use when many parties need to verify but only one can issue.

What PASETO fixes, concretely

JWT problemPASETO answer
alg: none bypassNo alg field exists; the version pins the algorithm.
RS256↔HS256 confusionlocal and public are distinct purposes; you can't cross them.
Weak-algorithm choicesEach version hard-codes modern crypto (v4 uses Ed25519 / XChaCha20).
"Is the payload secret?" ambiguitylocal is encrypted; public is explicitly not.

The claims themselves are still JSON, so PASETO keeps JWT's ergonomics — standard registered claims like exp, iss, and aud work the same way, and you still validate them. You lose *nothing* semantically; you lose only the dangerous knobs.

The footer and implicit assertions

PASETO's footer is authenticated but not encrypted — a good place for a key identifier so verifiers know which key to use (analogous to JWT's kid). Newer versions also support implicit assertions: extra data bound into the signature/encryption but not stored in the token, so a token is only valid in the context it was issued for.

When to choose PASETO — and when JWT is fine

Reach for PASETO when: - You're starting fresh and want secure defaults with no configuration to get wrong. - You need encrypted claims (local) and don't want to hand-roll JWE. - Your team has been bitten by JWT validation mistakes before.

Stick with JWT when: - You need the enormous ecosystem — OIDC, JWKS, gateways, and identity providers overwhelmingly speak JWT. - You're integrating with existing systems that issue or expect JWTs. - Your JWT usage is already locked down (pinned algorithm allowlist, strong keys, full claim validation) — a correctly-used JWT is secure; PASETO just makes "correctly" the only option.

The honest summary: JWT is secure when used perfectly and dangerous when used carelessly; PASETO narrows the gap between those two by removing the careless path. For an existing, well-configured JWT stack the upgrade is optional; for a greenfield service it's a sensible default.

For the JWT side of this comparison see JWT tokens explained, JWT vulnerabilities, and where to store tokens.

Frequently asked questions

PASETO (Platform-Agnostic SEcurity TOkens) is a stateless token format designed as a safer alternative to JWT. Instead of letting each token declare its algorithm, PASETO ties the cryptography to a fixed version and a purpose (local for encryption, public for signatures), eliminating whole classes of JWT attacks.

PASETO has no algorithm header for an attacker to modify — the version string determines the algorithm, and encrypted (local) versus signed (public) tokens are separate purposes that can't be swapped. Because the crypto isn't negotiable, those JWT attacks have nothing to exploit.

local uses symmetric encryption with a shared secret and keeps the claims confidential — best when one party both issues and reads tokens. public uses an asymmetric signature verifiable with a public key but does not encrypt the claims — best when many parties verify but only one issues.

Not necessarily. If your JWT implementation already pins algorithms, uses strong keys, and validates all claims, it's secure. PASETO is most compelling for new projects that want safe defaults, or teams that need encrypted claims without the complexity of JWE. JWT still wins on ecosystem support.

Yes. PASETO carries JSON claims just like JWT, including standard ones like exp, iss, and aud, so you validate them the same way. Only the envelope and cryptographic choices differ.

Try JSONKit — JSON Developer Tools

Format, validate, convert and diff JSON. Instant, accurate and 100% private.