Skip to content
BetterPass logo
Token Security

JWT vs PASETO vs SAML vs Opaque Tokens: How to Choose

16 min readBetterPass Security Team
Banner comparing JWT, PASETO, SAML assertions, and opaque tokens
Banner comparing JWT, PASETO, SAML assertions, and opaque tokens

Quick — which of these is your auth system running on right now: a JWT, a PASETO, an opaque token, or a SAML assertion?

If you had to think for more than a second, this guide is for you. And honestly, even if you answered instantly, there's a good chance your answer is "it depends on which endpoint you're talking to." Most real-world systems don't run one token type. They run two or three, quietly, and nobody on the team can explain exactly why anymore.

That's normal. Token formats get picked in the middle of a sprint, survive five rewrites, and become the kind of thing you inherit rather than choose. But tokens are the security boundary your entire application sits behind. They're worth understanding properly — because picking the wrong one doesn't just cost you performance. It can quietly create security holes that take years to surface.

This is a practical, no-fluff comparison of the four token approaches you'll actually meet in 2026 — what each one is really for, where it shines, and where it'll bite you.


The Short Answer

Here's the whole decision in one breath. We'll justify it below.

  • Opaque tokens when you need instant, guaranteed revocation — sessions, API keys, anything you want to kill the moment it's stolen.
  • JWT when you need stateless, self-contained credentials across many services, and you'll enforce strict signature verification.
  • PASETO when you want everything JWT gives you but with the footguns removed — no algorithm negotiation, no accidental vulnerabilities.
  • SAML when the enterprise SSO world forces your hand — legacy identity providers, federated partners, and compliance checklists that name it specifically.

And the honest follow-up: you usually don't have to pick just one. Mixing opaque access tokens with JWT-based ID tokens is the default OAuth/OpenID Connect pattern for a reason.


What Are We Even Comparing?

Before diving into the weeds, sort these four into two buckets — it answers 80% of "which should I use" questions on its own.

Self-contained tokens (JWT, PASETO) carry their own data. The token itself holds claims like user ID, roles, and expiration. Any service can validate it locally — no database lookup required.

Reference tokens (opaque tokens) are just random strings. They point to a session stored server-side. Think of it like a coat-check ticket: the ticket means nothing on its own, but the server holding the corresponding coat knows exactly what it represents.

SAML is a different animal entirely. It's not really a token format — it's an XML-based protocol for exchanging authentication and authorization data between an Identity Provider (IdP) and a Service Provider (SP), most commonly in enterprise single sign-on.


JWT: The Popular Kid With Baggage

JWT (JSON Web Token) is a compact, URL-safe token format defined in RFC 7519. It's three base64-encoded parts separated by dots: a header, a payload, and a signature.

eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

Why people love it

  • It's stateless. No database call to validate a session — a natural fit for microservices and distributed systems.
  • It's everywhere. Libraries exist for essentially every language, and identity providers, API gateways, and cloud services speak JWT natively.
  • It's debuggable. Once decoded, the payload is human-readable, which makes tracing problems easier.

The catch: encoded is not encrypted

The single most important fact about JWT: a normal signed JWT does not hide its payload. Anyone who obtains the token can base64-decode the middle part and read every claim. Putting a secret in a JWT is like writing it on a postcard and putting a wax seal over the text. The signature proves the token hasn't been tampered with — it does not grant confidentiality.

Where it bites

  • Algorithm agility is a vulnerability, not a feature. Because the header says which algorithm to use, your code must handle an attacker swapping RS256 for HS256 (algorithm confusion) or setting alg: none. Mitigations exist; the fact that they need to exist is the problem.
  • Revocation is awkward. A signed JWT is valid until exp. "Logging someone out" means maintaining a denylist — which defeats the statelessness you chose it for.
  • Tokens bloat. Every claim you add rides along on every single request. Chubby JWTs are a real latency tax.

JWT isn't insecure by design. The RFC is fine. It's that its flexibility gives developers enough rope to hang themselves. If you use JWT, verify the signature on every request, pin the allowed algorithms, keep payloads small and unclassified, and keep lifetimes short. Use our JWT Decoder to inspect the header, payload, and registered claims of any JWT right in your browser.

Best for: modern REST APIs, OAuth/OIDC, microservices, and anything that needs distributed, stateless validation.


PASETO: JWT's Corrective Sequel

PASETO (Platform-Agnostic Security Token) was created specifically as a response to JWT's footguns. Where JWT lets you choose the algorithm (and choose wrong), PASETO removes that choice entirely. Every PASETO version has one, and only one, sanctioned cryptographic recipe.

PASETO tokens come in versions (v4 is current), and each version has two purposes:

  • local — encrypted, symmetric-key tokens (nobody can read the contents without the key)
  • public — signed, asymmetric-key tokens (anyone can read, only the issuer can sign)

A PASETO token looks like this:

v4.local.bU9Ug9V4uOwPz6BSDbNVn4W_...

Why teams switch

  • No algorithm confusion attacks are possible. The version string locks in the crypto suite. An attacker can't downgrade you from Ed25519 to HS256 because the format doesn't allow the negotiation in the first place.
  • No "signed or encrypted?" ambiguity. v4.public means signed. v4.local means encrypted. The distinction is structural, not configurational.
  • Simpler mental model. You don't need to be a cryptography expert to use it safely.

The tradeoffs

  • Smaller ecosystem. Libraries exist for all major languages, but they're younger and less battle-tested than JWT's.
  • Enterprise adoption is thin. Okta, Entra ID, Auth0, and Keycloak hand you JWTs and SAML assertions — not PASETOs.
  • Same statelessness trade-off. Revocation is still the weak point: a signed PASETO is still valid until it expires.

The sweet spot for PASETO is greenfield services where you control both the issuer and the verifier, and you'd rather start with a safe design than inherit a legacy one. Inspect v4.public signatures and decrypt v4.local payloads locally with our PASETO Decoder.

Best for: security-sensitive greenfield systems where you control both sides and want the dangerous choices removed.


SAML: The Enterprise Veteran

SAML predates JWT by roughly a decade and was purpose-built for enterprise single sign-on. It uses XML to package assertions — statements about a user's identity, attributes, and authorization — and passes them between an Identity Provider and a Service Provider, usually over a browser redirect flow.

A typical flow: a user tries to log into an app (the SP), gets redirected to their company's identity provider (Okta, Azure AD, Ping Identity), authenticates there, and the IdP sends back a signed XML assertion confirming who they are. The SP verifies the signature and grants access.

Why enterprises still run on it

  • It's battle-tested. SAML 2.0 has been the SSO backbone of corporate environments since 2005.
  • Federation across organizational boundaries. A contractor's company IdP can authenticate them into your internal app without you ever managing their password.
  • Rich attribute-based access control. Assertions carry group memberships, roles, and custom attributes.

Why it feels dated

  • XML is verbose and painful to parse. XML Digital Signatures have their own history of vulnerabilities — most famously XML Signature Wrapping attacks, where attackers manipulate the structure so a valid signature appears to cover content it doesn't.
  • It's browser-coupled. SAML is built around redirects and server-side handling, so it's clunky for mobile apps and API-to-API auth — and forcing it into that role is a common mistake.
  • Setup is genuinely complex. Exchanging metadata, certificates, and entity IDs trips up even experienced engineers. Debugging a broken assertion is an archaeology project.

If a partner, a compliance framework, or a legacy identity provider names SAML, use SAML — you have no real alternative, and it works fine when configured properly. Otherwise, don't reach for it. Our SAML Assertion Decoder handles base64 and DEFLATE decompression with syntax-highlighted XML — the fastest way to read what an IdP actually sent you during SSO debugging.

Best for: enterprise and federal SSO, federated partners, and integrations where the identity provider only speaks SAML.


Opaque Tokens: Boring, But Often the Right Call

An opaque token is just a random string. No embedded data, no structure to decode. Back to the coat-check ticket: it means nothing on its own, but the server holding the corresponding session data knows exactly what it represents.

a8f5f167f44f4964e6c998dee827110c

Why "boring" is a feature

  • Instant revocation. Since validation requires a server-side lookup, killing a session is as simple as deleting a row from a database or cache. This is the single biggest advantage opaque tokens have over JWT and PASETO.
  • No data leakage risk. There's no payload to decode, so there's nothing sensitive sitting in the token itself — even if it's intercepted or logged by accident.
  • Simplicity. No signature verification, no algorithm choices, no version strings. Just look it up.

The tradeoff that matters

Every validation is a round-trip to wherever the session lives — Redis, a database, an in-memory cache. That adds latency and a scaling dependency that self-contained tokens don't have. In a microservices architecture it often means a shared session store every service can reach, or a centralized auth service all requests funnel through.

Use them right

  • Store only a hash of the token server-side (like a password hash), not the token itself — otherwise a leaked database is a dump of working credentials.
  • Generate them with a real CSPRNG. Math.random() is not cryptographically secure, and hand-typed strings are worse.
  • Go roughly 32 characters (about 192 bits) as a sensible floor for tokens you can't afford to have guessed.

Our Opaque Token Generator creates CSPRNG-backed tokens sized for sessions, API keys, or OAuth 2.0 bearer credentials — a good way to see what a well-formed token looks like before you wire up your own minting code.

Best for: sessions, API keys, and any system where "kill this credential right now" needs to actually work immediately.


Side-by-Side Comparison

Dimension JWT PASETO Opaque Token SAML Assertion
What it is Signed/encoded claim format Signed/encrypted claim format Random string + server-side state XML identity assertion (protocol)
Verification Stateless (shared secret or public key) Stateless (Ed25519 public key) Stateful (DB/cache lookup) Signature validation by SP
Revocation Hard (denylist or short TTL) Hard (denylist or short TTL) Instant (delete the record) Short-lived by design; conditions + logout
Data exposure Readable by anyone (encoded, not encrypted) Encrypted in v4.local; readable in v4.public None — server holds the meaning Readable XML (signed, not encrypted)
Algorithm flexibility High (the source of attacks) None (fixed per version) N/A Fixed by profile/config
Ecosystem Massive Growing Universal Enterprise-legacy
Best for Stateless APIs, OIDC ID tokens, JWKS Greenfield stateless services Sessions, API keys, anything revocable Enterprise/federal SSO
Worst at Revocation, algorithm confusion Ecosystem, enterprise adoption Offline checks, stateless scaling Mobile apps, lightweight APIs

How to Choose: A Decision Framework

Forget "best token" — that's the wrong question. The right question is: "What does this specific boundary need?" Work through these in order.

1. Does an enterprise partner, compliance rule, or legacy IdP require SAML?

Then the decision is made for you. Integrate SAML at that boundary, keep the XML handling contained, and use good tooling to debug it. Don't fight it.

2. Do you need to kill a credential instantly if it's compromised?

If the answer is "yes, immediately, with no window," you want opaque tokens. This is the session default: block a stolen API key or revoke a leaked access token by deleting a server-side record. The instant the record is gone, the token is worthless.

3. Do many services need to verify a token without a shared lookup?

Then you need stateless verification, which rules out opaque tokens. Between the two stateless formats:

  • PASETO if you're building something new, control both ends, and want the safest possible default.
  • JWT if you're integrating with an existing identity provider or need the broadest ecosystem — just enforce signature verification and algorithm pinning ruthlessly.

4. Does your token need to be a genuine secret?

Opaque. Always. Don't put credentials or secrets inside a readable token format, even a signed one. A signature proves integrity; it doesn't grant secrecy.

5. Not sure, and just building an MVP?

Start with opaque tokens behind a simple session store. They're the easiest to reason about, the easiest to revoke, and you can migrate to JWT or PASETO later once you understand your real scaling needs. Premature statelessness is a classic case of solving a problem you don't have yet.

6. Lost in OAuth/OpenID Connect?

Stop and use the standard pattern: a short-lived access token (opaque or JWT — your choice) plus a refresh token, plus a JWT ID token the client uses to read the user's identity. Mixing is normal and correct: opaque for revocable access, JWT/PASETO for stateless claims you must verify offline, and SAML only where the ecosystem demands it.


Real-World Combinations That Actually Work

A typical B2C SaaS: session cookie = opaque token, stored hashed in a sessions table. No JWT anywhere, and it works great. Revocation is instant and implementation is trivial.

A microservices platform: each service is stateless and scales independently. Access is a short-lived PASETO (or JWT) signed by the gateway and verified with its public key in each service — no shared session database in the hot path. A separate opaque, revocable credential handles long-lived machine-to-machine calls.

An enterprise SSO portal: Okta (or Entra ID, or ADFS) is the IdP; the portal integrates with downstream apps over SAML. Internally, the portal's own API uses opaque session tokens or short-lived JWTs. Two protocols, three formats, one company.

A mobile app backed by an API: the app talks OIDC to an identity provider, receives a JWT ID token (readable, so the app can show your name and avatar), and an access token the API treats as opaque — introspecting it against the auth server rather than verifying claims locally. The classic, correct pattern.


Common Mistakes to Avoid

Storing secrets in a JWT payload

Encoding is not encryption. A JWT's middle section is base64 — decode it and read it. Never put passwords, API keys, or PII you're not comfortable being public into an authentication JWT. Use v4.local or JWE if you genuinely need confidentiality — or don't put it in the token at all.

Believing "signed" means "secure"

A signature proves the token hasn't been modified since it was issued. It says nothing about whether the issuer was who you think it was, whether you pinned the right algorithm, or whether the contents were appropriate to put there in the first place. Signature verification is necessary, not sufficient.

Treating revocation as optional

If you chose stateless tokens and never implemented a revocation path, a leaked token works until it expires — hours or days later. Either shorten your TTL aggressively, add a denylist for your most sensitive actions, or switch that boundary to opaque tokens.

Using Math.random() for opaque tokens

Opaque tokens are only as strong as their randomness. Use the Web Crypto API or your platform's CSPRNG, and give them enough length.

Storing opaque tokens in plaintext

Store only a hash, the way you'd store a password. If your sessions table leaks and you stored raw tokens, the attacker gets working credentials for every active session. One extra hash step turns a catastrophic leak into an inconvenience.

Copying the first SAML library without understanding the binding

SAML has multiple bindings, encodings, and profiles. If an integration mysteriously fails, check the encoding (base64? DEFLATE?), check the profile (Web SSO vs ECP), and decode the actual assertion to see what the IdP really sent.

Picking a format because a blog post said it was "best"

Every one of these formats has a legitimate home. A "JWT is bad, use PASETO" article ignores that your identity provider only issues JWTs. Match the format to the boundary, not to the hype.


Frequently Asked Questions

Is JWT encrypted?

No. JWTs are typically signed and encoded, not encrypted. The payload is base64-encoded JSON anyone can decode and read. Encrypted JWTs exist (JWE format), but the JWT most people use is readable. If you need confidentiality, use JWE or PASETO v4.local.

Is PASETO more secure than JWT?

PASETO removes an entire class of configuration mistakes — there's no algorithm negotiation, so "alg: none" and algorithm-confusion attacks are structurally impossible. But overall security still depends on key management, validation, storage, and the rest of the system. A properly locked-down JWT is secure too; PASETO just makes the secure path the default.

When should I use an opaque token instead of a JWT?

Whenever you need instant revocation, want to keep claims off the wire, or are minting a genuine secret like an API key. The cost is a database (or cache) lookup on every request. If you can't tolerate a shared lookup in your request path, a stateless JWT or PASETO is the better trade.

Do I still need SAML if I use OIDC?

Not necessarily. OpenID Connect is the modern replacement for many SAML use cases, especially mobile apps and SPAs. But if a partner, compliance framework, or legacy identity infrastructure requires SAML, you can't simply switch them — SAML lives on for exactly that reason.

What is a SAML assertion, exactly?

It's the XML document an Identity Provider hands to a Service Provider saying "this user authenticated, and here are the identity attributes they're entitled to claim." It's the SAML protocol's equivalent of a token — signed, usually base64-encoded, and frequently DEFLATE-compressed in browser redirect flows.

Are session cookies opaque tokens?

In practice, yes. A session cookie is a random identifier the server looks up in a session store — which is the definition of an opaque token. Same concept, delivered through the browser's cookie mechanism.

Which is most secure: JWT, PASETO, opaque, or SAML?

None of them on their own. Security comes from how you use the format: strict signature verification, proper key management, short lifetimes, instant revocation where you need it, and never storing secrets where they can leak. That said, PASETO removes the most exploitable default (algorithm negotiation), and opaque tokens are the safest choice when you need revocation.


The Bottom Line

Every auth system in production right now runs at least one of these four, and most run two or three. None of them are "bad" — they're tools with different trade-offs, and choosing well means matching the trade-off to the boundary you're protecting:

  • Reach for opaque tokens when revocation matters most — sessions, API keys, secrets.
  • Reach for JWT when you need the ecosystem, the standards, and stateless verification — and you'll verify signatures with discipline.
  • Reach for PASETO when you want statelessness with the dangerous choices removed — and you control both issuer and verifier.
  • Reach for SAML when the enterprise around you demands it — and keep good decoding tooling close.

The teams that build the safest systems don't pick a "best" format. They pick the format that matches each authentication boundary, document why they chose it, and verify every token — signature and expiration included — on every request.

Ready to inspect your own tokens? Decode and verify JWTs, PASETO v4 tokens, SAML assertions, and OIDC ID tokens — or generate strong opaque tokens — entirely in your browser with the free BetterPass token tools. Nothing you paste ever leaves your device.