Migrating from JWT to PASETO: Why I Made the Switch

Clare Mburu
4 min readNov 1, 2024

--

I’ve recently made the switch from using JSON Web Tokens (JWT) to Platform-Agnostic Security Tokens (PASETO) v4 for authentication in web applications. This decision wasn’t easy, but after careful consideration of the pros and cons, I believe PASETO offers significant advantages over JWT. Let me walk you through the reasons behind this migration and provide some code examples to illustrate the differences.

Understanding JWT Limitations

Before diving into PASETO, let’s briefly review some limitations of JWT:

1. Weak algorithms: JWT offers many signing algorithms, some of which are known to be vulnerable.

2. Trivial forgery: JWT’s structure makes it easy for attackers to bypass signature verification.

3. No encryption: JWT payloads are only base64-encoded, not encrypted.

4. Algorithm negotiation: JWT includes the signing algorithm in the token header, allowing potential attacks.

Introducing PASETO

PASETO addresses these issues and provides a more secure and straightforward approach to token-based authentication.

Why Migrate from JWT to PASETO v4?

Enhanced Security

One of the primary reasons for migrating to PASETO v4 is its improved security profile compared to JWT.

- No Algorithm Negotiation: PASETO prevents downgrade attacks by specifying the cryptographic algorithm upfront .

- Mandatory Authentication: All tokens in PASETO require mandatory authentication, enhancing overall security.

- Built-in Support for Encrypted Tokens: PASETO provides native support for encrypted tokens, offering an extra layer of protection.

Implementation Example

Let’s compare JWT and PASETO implementations in Node.js:

JWT Implementation

import jwt from 'jsonwebtoken';

// Creating a JWT
function createToken(payload) {
return jwt.sign(payload, 'your-secret-key', { expiresIn: '1h' });
}

// Verifying a JWT
function verifyToken(token) {
try {
return jwt.verify(token, 'your-secret-key');
} catch (error) {
console.error('Token verification failed:', error.message);
return null;
}
}

// Usage
const payload = { userId: 123, username: 'johndoe' };
const token = createToken(payload);
console.log('Created JWT:', token);

verifyToken(token).then(decoded => {
console.log('Decoded JWT:', decoded);
}).catch(err => {
console.error('Invalid JWT:', err.message);
});

PASETO Implementation

import * as paseto from 'paseto';
import UserToken from "../models/tokenModel.js";
import { getkgenOne } from '../controllers/tokenController.js';

const { V4 } = paseto;
const { sign, verify,generateKey } = V4;

// Function to generate keys
async function generateKeyPair2() {
const genkey = await generateKey('public',{'format':'paserk'});
return { genkey };
}

const aw = await generateKeyPair2()

// Helper function to sign tokens
async function signToken(payload) {
const prk1 = aw.genkey.secretKey

// Calculate expiration time for 1 hour from now
const expTime = Math.floor(Date.now() / 1000) + 3600;

// Add exp claim to the payload
payload.exp = expTime.toString();

return await sign(payload, prk1 );
}

const generateToken = async(res, userId)=>{

const payload = {userId}
const jsonString = JSON.stringify(payload);
const buffer = Buffer.from(jsonString, 'utf8');
const token = await signToken(buffer);
return token;

}

// Generate Token
const genToky = async(res, userId) =>{
try {
const privateKey1 = aw.genkey.secretKey
const publicKey1 = aw.genkey.publicKey

const token = await generateToken(res, userId)

const ptkgen1 = new UserToken({
userId:userId,
token:token,
privateKey:privateKey1,
publicKey:publicKey1,

});

const ptkgen2 = await ptkgen1.save()

return {publicKey1,privateKey1,token}


} catch (error) {
console.error(error)
}
return null; // Return null if an error occurs
}

// Verify Token
const verTok = async(token)=>{

const pk1 = aw.genkey.publicKey

// Verify the PASETO token
const decoded = await verify(token, pk1);

return decoded
}

export {genToky,verTok};


// Usage Example


// Protect Middleware

import asyncHandler from './asyncHandler.js';
import User from '../models/userModel.js';
import { verTok } from '../utils/generateToken.js';

const protect = asyncHandler(async (req, res, next) => {

const authHeader = req.headers.authorization;

if (!authHeader || !authHeader.toLowerCase().startsWith('bearer ')) {
console.error('Invalid authorization header');
return res.status(401).json({ error: 'No token provided' });
}

const token = authHeader.split(' ')[1];

if (!token) {
console.error('Token not found after splitting');
return res.status(401).json({ error: 'No token provided' });
}

try {
const decoded = await verTok(token)

// Get the user ID from the payload
const userId = decoded;
const user = await User.findOne(userId).select('-password');

if (!user) {
throw new Error('User not found');
}

req.user = user;
next();
} catch (error) {
console.error('PASETO verification failed:', error.message);
if (error.name === 'InvalidTokenError') {
return res.status(401).json({ error: 'Invalid token' });
}
return res.status(500).json({ error: 'Internal Server Error' });
}
});

export { protect};

Benefits of Migrating to PASETO V4

1. Enhanced Security: PASETO addresses many common JWT vulnerabilities out of the box.

2. Simplicity: With fewer options to choose from, PASETO reduces the risk of misconfiguration.

3. Future-proofing: PASETO uses modern cryptographic primitives, ensuring better long-term security.

4. Flexibility: While PASETO offers built-in encryption, it also supports custom payloads and formats.

Conclusion

I believe the enhanced security features and simplified implementation of PASETO outweigh the migration efforts. However, the choice between JWT and PASETO should ultimately depend on your project requirements, existing infrastructure, and security needs.

If you’re building a new project or considering upgrading from JWT, I highly recommend exploring PASETO v4 as a secure and simpler alternative.

Remember, security is an ongoing process. Regularly review and update your authentication methods to ensure they align with current best practices and evolving threats.

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

--

--

Clare Mburu
Clare Mburu

Written by Clare Mburu

I am a passionate fullstack developer with over 5 years of experience building responsive websites with a focus on React, Node, Mongo and Express.

No responses yet

Write a response