Modern web applications rely heavily on secure token-based authentication to protect user data and API endpoints. While JSON Web Tokens (JWT) have dominated this space for years, developers increasingly face challenges with their security pitfalls and implementation complexity. Enter PASETO (Platform-Agnostic Security Tokens), a modern token format designed to address JWT’s shortcomings while maintaining simplicity and cryptographic rigor. In this guide, we’ll explore PASETO’s architecture, compare it to JWT, and demonstrate practical implementations in Node.js.
What Is PASETO?
It’s a relatively new security protocol (currently a draft RFC) for creating secure and stateless tokens that can be safely shared over the web. It’s rapidly gaining adoption in the security community and is considered a simpler, more secure alternative to JSON Web Tokens (JWTs). It allows you to condense JSON data into a single, tamperproof token for easy and safe internet sharing
The Problem with JWT
JWTs gained popularity due to their stateless nature and flexibility, but their design flaws have led to widespread security issues.
For example:
Algorithm Selection (Ciphersuite Agility): JWTs include an algorithm (alg) value in their header, which specifies how the token is signed or encrypted. This value can be changed by an attacker to none (no signature), a weaker algorithm, or even to a symmetric signature using an RSA public key, leading to potential vulnerabilities. While protocols like OAuth and OpenID Connect mitigate this issue in their specific contexts, it remains a general concern with the JWT specification.
Misuse of JWTs: JWTs are sometimes improperly used for stateless sessions or storage, particularly in Single Page Applications (SPAs), which can introduce security risks.
Revocation Challenges: Once a JWT is issued, it can be difficult to revoke it, as servers typically don’t keep track of issued tokens in a stateless system. If a user’s credentials are compromised, their existing JWT might remain valid until it expires. There can be some workarounds like blacklists or dedicated revocation services but they add unnecessary complexity.
Developers Making Poor Security Choices: The flexibility of the JOSE specifications, including JWT, forces developers to make numerous low-level security and cryptography decisions, increasing the risk of introducing security issues due to incorrect or poor configurations and a lack of expertise.
No built-in key rotation: Short-lived tokens require complex refresh mechanisms, while long-lived tokens risk being stolen and reused.
PASETO solves these problems by enforcing secure defaults, eliminating ambiguous parsing, and simplifying key management. Unlike JWT, PASETO strictly defines which algorithms to use per version, eliminating risky choices.
PASETO Token Structure
A PASETO token consists of four components:
- Version: Specifies the cryptographic protocol (e.g., v1/v2/v3) This version information helps understanding how the token was created and which algorithms are in use.
- Purpose: Local (encrypted) or public (signed).
- local (symmetric): This indicates that the token is intended for symmetric encryption, meaning it’s encrypted and decrypted using a shared secret key.
- public (asymmetric): This indicates that the token is intended for asymmetric signing, meaning it’s signed using a private key and can be verified using a corresponding public key.
- Payload: The third section contains the actual token contents (encrypted or signed data), which is also referred to as the payload. For local PASETOs, this payload is an encrypted blob of JSON.
If you have the correct key, you can decrypt this section to view the original JSON data. For public PASETOs, the payload contains the JSON data that is digitally signed but not encrypted. This allows anyone with the token to see its contents, but they cannot modify it without invalidating the signature.
The payload often includes claims, which are simply JSON keys that carry information. The PASETO standard defines several reserved claims like
- iss (Issuer)
- sub (Subject)
- aud (Audience)
- exp (Expiration)
- nbf (Not Before)
- iat (Issued At)
- jti (Token ID)
- kid (Key-ID)
- Footer (optional): Non-sensitive metadata. The final, optional fourth section is called the footer. It can store additional metadata, which is not encrypted.
Key Features
Secure by Default: A key feature of PASETO is that it explicitly specifies which cryptographic algorithms should be used for each version and purpose (local or public)3 …. This eliminates the risk of algorithm confusion, a known vulnerability in JWT where improper algorithm choices can lead to security issues. Only vetted algorithms (e.g., XChaCha20-Poly1305, Ed25519) are allowed which ensures tokens remain secure and less susceptible to cryptographic vulnerabilities.
Deterministic Parsing: The process of breaking down a PASETO token into its constituent parts and then processing the payload (either decrypting or verifying) would follow a predictable and consistent set of rules based on the initial version and purpose indicators. This predictability is crucial for security and proper implementation.
Stateless or Stateful: Supports both short-lived tokens and revocation via stored claims.
Implementing PASETO in Node.js
Install Paseto
npm install paseto
Generate Asymmetric Key Pair
const { V4 } = require('paseto');
const { generateKeyPair } = V4;
(async () => {
const { publicKey, secretKey } = await generateKeyPair('ed25519');
console.log('Public Key:', publicKey.export());
console.log('Private Key:', secretKey.export());
})();
Create a Token
const { V4 } = require('paseto');
const { generateKeyPair } = V4;
(async () => {
const { secretKey } = await generateKeyPair('ed25519');
const token = await V4.sign(
{
sub: 'user-123',
role: 'admin',
exp: '2025-05-01T00:00:00Z',
},
secretKey,
{
footer: 'my-footer-data',
}
);
console.log('Token:', token);
})();
Verify the Token
const { V4 } = require('paseto');
const { generateKeyPair } = V4;
(async () => {
const { secretKey, publicKey } = await generateKeyPair('ed25519');
const token = await V4.sign(
{
sub: 'user-123',
role: 'admin',
exp: '2025-05-01T00:00:00Z',
},
secretKey
);
const payload = await V4.verify(token, publicKey);
console.log('Verified Payload:', payload);
})();
Symmetric (Local) PASETO
const { V4 } = require('paseto');
const { generateKey } = V4;
(async () => {
const key = await generateKey('local');
const token = await V4.encrypt(
{ userId: 'abc123', exp: '2025-05-01T00:00:00Z' },
key
);
console.log('Token:', token);
const payload = await V4.decrypt(token, key);
console.log('Payload:', payload);
})();
PASETO vs. JWT: Key Differences

Feature | JWT (JSON Web Token) | PASETO (Platform-Agnostic Security Token) |
Structure | Single, generic structure with Header, Payload, and Signature. | Versioned approach with specific purposes (local/public). Consists of Header (version, purpose, algorithm), Payload, and optional Footer. |
Algorithm Handling | Ciphersuite agility: Algorithm (alg) specified in the header, allowing for flexibility but also potential vulnerabilities like the “none” algorithm. Developers choose the algorithm. | Algorithm confusion eliminated by specifying algorithms per version and purpose. Enforces secure defaults based on purpose (local or public). |
Security | Can be secure if implemented correctly.Requires careful implementation to avoid vulnerabilities related to algorithm choice and key management.Potential for signature verification bypass. | Designed with a focus on security.Promotes better security practices by design.Aims to mitigate vulnerabilities present in JWT. |
Key Management | Requires careful implementation to avoid vulnerabilities if the secret key is compromised. | Promotes better key management practices by design due to the distinct local (symmetric) and public (asymmetric) token types. |
Stateful/Stateless | Flexible structure accommodates both stateful and stateless applications. Often misused for stateless sessions. | Local tokens designed for stateful, server-side sessions. Public tokens intended for stateless applications using public-key cryptography. |
Revocation | Stateless nature makes revocation challenging.Requires additional mechanisms like blacklists, token binding, or dedicated revocation services. | Local tokens: Server can maintain a list of issued tokens, simplifying revocation.Public tokens: Stateless, requiring mechanisms similar to JWT for revocation. |
Configuration Defaults | Allows for potential misconfigurations and vulnerabilities if not implemented carefully. | Enforces secure algorithms and configurations by default. |
Ease of Implementation | Generally perceived as simple to implement due to widespread familiarity and available libraries. | Designed with ease of implementation in mind. |
Ecosystem Support | Extensive support across numerous programming languages, frameworks, and libraries.Larger community and readily available resources. | Ecosystem is expanding, with libraries and tools becoming increasingly available.May not yet match the breadth of JWT support. |
Misuse Potential | Widely misused, leading to security impacts. | Specification clearly defines how it should and should not be used to reduce misuse.Designed as single-use tokens, not for long-lived access tokens. |
Standardization | Open standard (RFC 7519).Part of the JOSE family of specifications. | Was submitted as a draft RFC but was not formally adopted and the draft has expired. Continues as its own specification. |
Stateless vs. Stateful
While PASETO tokens can be stateless, pairing them with a session database improves security for high-risk applications. For example:
app.get('/api/user', async (req, res) => {
const token = req.headers.authorization.split(' ')[1];
const payload = await verify(token, secretKey);
const user = await db.users.find(payload.userId);
// Check revocation status
if (user.tokenVersion !== payload.v) {
return res.sendStatus(401);
}
res.json(user);
});
Conclusion
PASETO offers a robust alternative to JWT by eliminating insecure defaults and simplifying secure implementation. Its rigid structure and modern cryptography make it ideal for developers prioritizing security without sacrificing ease of use. While JWT remains popular, PASETO’s growing adoption by frameworks and security experts signals a shift toward more reliable token formats.
Additional Resources
- PASETO RFC Specification
- PASETO.js GitHub Repository
- Okta’s PASETO Introduction
- JWT vs. PASETO: A Security Deep Dive
By adopting PASETO, developers can mitigate common authentication vulnerabilities while maintaining scalability and performance. Whether you’re building a small API or a enterprise-grade system, PASETO provides the tools to secure your application with confidence.