# PASETO

Platform-Agnostic Security Tokens, designed by Scott Arciszewski (Paragon Initiative) as a direct response to the design problems of JWT and the broader JOSE family. The spec lives at [paseto.io](https://paseto.io/). PASETO is the recommendation that the [[samsch-jwt-auth-gist|samsch gist]] and similar critiques point to whenever a real short-lived signed-token use case exists — the reasonable replacement for JWT in the cases where signed tokens actually fit.

PASETO is not a session-management replacement. It does not change the underlying argument that you should use [[cookie-session-auth|cookie sessions]] for keeping browser users logged in and avoid [[jwt-for-sessions|JWTs as session tokens]]. PASETO is the tool for the residual ~5-minute use cases: SSO transports, password-reset links, email-verification links, capability tokens, service-to-service tokens.

## What's wrong with JWT that PASETO fixes

PASETO's design is structured as a list of decisions made the opposite of JWT's:

- **No `alg` field, no algorithm negotiation.** The token's *version* and *purpose* are the identifier. There is no way to ask the verifier to use a weaker algorithm, no way to confuse symmetric and asymmetric (the JOSE key-confusion attack), and no `alg: none`.
- **Versioned cryptographic suites.** Each PASETO version pins specific algorithms. v3/v4 are current — v3 for NIST suites (P-384 ECDSA, AES-CTR + HMAC), v4 for modern non-NIST (Ed25519, XChaCha20). There is no per-token algorithm choice to get wrong.
- **Two purposes, no more.** `local` (symmetric, encrypted) and `public` (asymmetric, signed). That's it. JOSE's matrix of JWS × JWE × algorithms is collapsed into four well-defined combinations across two versions.
- **Authenticated encryption by default for the symmetric case.** PASETO `v4.local` uses XChaCha20-Poly1305. JWE has many ways to get this wrong.
- **Footers and implicit assertions** for binding tokens to a specific context (audience, issuer, key ID) without those values becoming part of the malleable claim set.

## What it looks like

PASETO tokens look like JWTs at a glance — base64url-encoded segments separated by dots — but the structure encodes the version and purpose at the front:

```
v4.public.eyJkYXRhIjoidGhpcyBpcyBhIHNpZ25lZCBtZXNzYWdlIn0.<sig>
```

The first two segments (`v4.public`) are the version and purpose; everything else follows from that choice. The verifier doesn't read an algorithm hint from the token; it knows what algorithm `v4.public` means and refuses to verify under any other one.

## When to reach for PASETO

- Single-sign-on transports — short-lived bearer tokens that move a login from one host or service to another.
- Password-reset, magic-link, and email-verification tokens.
- Signed capability tokens (download URLs, action tokens with embedded expiry).
- Service-to-service authentication in microservice architectures (alternative to mTLS or to JWT).

For all of these the ~5-minute lifetime fits, and the value of having no algorithm-choice footgun outweighs the relatively minor friction of picking a less-well-known spec.

## When not to reach for PASETO

For browser session management, use [[cookie-session-auth]]. PASETO doesn't fix the lifetime mismatch or the "stateless is a lie" problem that motivates avoiding [[jwt-for-sessions]] — those are properties of using bearer tokens for long-lived sessions, regardless of which signed-token format carries them.

## Related

- [[jwt-for-sessions]] — the anti-pattern PASETO does *not* fix; for sessions you still want cookies
- [[cookie-session-auth]] — the right tool for browser sessions
- [[samsch-jwt-auth-gist]] — short gist that recommends PASETO for the residual short-lived-token cases
