Step-by-step Guide: Creating a PASETO (Platform-Agnostic Security Token) in Express.js
Source: Dev.to

1. Install dependencies
Run this once:
npm install express paseto tweetnacl dotenv
2. Create a .env file
PORT=3000
3. Create an Express server with PASETO
Create a file named server.js:
import express from "express";
import { V2 } from "paseto";
import nacl from "tweetnacl";
import dotenv from "dotenv";
dotenv.config();
/**
* Generate an Ed25519 key pair with tweetnacl
*/
console.log("🟡 Generating Ed25519 key pair (v2.public) ...");
const keyPair = nacl.sign.keyPair(); // Uint8Arrays
const privateKey = Buffer.from(keyPair.secretKey);
const publicKey = Buffer.from(keyPair.publicKey);
console.log("✅ Keys ready, starting Express...");
const app = express();
app.use(express.json());
// issue token
app.post("/token", async (req, res) => {
try {
const payload = {
userId: req.body.userId,
role: req.body.role,
issuedAt: new Date().toISOString(),
};
const token = await V2.sign(payload, privateKey, {
issuer: "my-app",
audience: "users",
expiresIn: "1h",
});
res.json({ token });
} catch (err) {
console.error("❌ Token generation failed:", err);
res.status(500).json({ error: err.message });
}
});
// verify token
app.post("/verify", async (req, res) => {
try {
const { token } = req.body;
const payload = await V2.verify(token, publicKey, {
issuer: "my-app",
audience: "users",
});
res.json({ valid: true, payload });
} catch (err) {
console.error("❌ Verification failed:", err);
res.status(401).json({ error: "Invalid or expired token" });
}
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => console.log(`🚀 Server running on http://localhost:${PORT}`));
4. Run the server
node server.js
You should see output similar to:
🟡 Generating Ed25519 key pair (v2.public) ...
✅ Keys ready, starting Express...
🚀 Server running on http://localhost:3000
5. Test the API
Generate a token
curl -X POST http://localhost:3000/token \
-H "Content-Type: application/json" \
-d '{"userId":123,"role":"admin"}'

Verify the token
Replace PASTE_YOUR_TOKEN_HERE with the token you received above.
curl -X POST http://localhost:3000/verify \
-H "Content-Type: application/json" \
-d '{"token":"PASTE_YOUR_TOKEN_HERE"}'

Tip: In production you should store the key pair securely instead of generating it on every startup. This demo setup is intended for learning how PASETO works.