PASETO: A New Era of Token-Based Authentication with Node.js and Express
Published: 2024-06-21 05:55:28

PASETO (Platform-Agnostic Security Tokens) is a modern alternative to JWT (JSON Web Tokens) that focuses on security and simplicity. Here's an example of how to use PASETO for token-based authentication in JavaScript.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1x7szd2kj0g7l6ybx5vs.png)
### Setup

1. **Install the necessary libraries**:
   - Use the `paseto.js` library for PASETO.
   - For simplicity, we'll use `Node.js` and `Express` to demonstrate a server-side implementation.

```bash
npm install paseto express body-parser
```

2. **Create the server**:

```javascript
// server.js
const express = require('express');
const bodyParser = require('body-parser');
const { V4 } = require('paseto');
const { generateKeyPair } = require('paseto/dist/lib/crypto/pair');

const app = express();
const port = 3000;

app.use(bodyParser.json());

let privateKey;
let publicKey;

(async () => {
  const keyPair = await generateKeyPair('v4.public');
  privateKey = keyPair.secretKey;
  publicKey = keyPair.publicKey;
})();

// Middleware to verify PASETO token
const authenticateToken = async (req, res, next) => {
  const token = req.header('Authorization').replace('Bearer ', '');
  try {
    const payload = await V4.verify(token, publicKey);
    req.user = payload;
    next();
  } catch (err) {
    res.status(401).send('Unauthorized');
  }
};

// Login route to generate PASETO token
app.post('/login', async (req, res) => {
  const { username, password } = req.body;
  // Replace with your own user verification logic
  if (username === 'admin' && password === 'password') {
    const token = await V4.sign({ username }, privateKey, { expiresIn: '1h' });
    res.json({ token });
  } else {
    res.status(401).send('Invalid credentials');
  }
});

// Protected route
app.get('/protected', authenticateToken, (req, res) => {
  res.json({ message: 'This is a protected route', user: req.user });
});

app.listen(port, () => {
  console.log(`Server running at http://localhost:${port}`);
});
```

### Explanation

1. **Key Pair Generation**:
   - The server generates a key pair for signing and verifying PASETO tokens using `generateKeyPair('v4.public')`.

2. **Login Route**:
   - The `/login` route verifies the username and password.
   - If valid, it generates a PASETO token using `V4.sign` and sends it to the client.

3. **Authentication Middleware**:
   - The `authenticateToken` middleware extracts the token from the `Authorization` header.
   - It verifies the token using `V4.verify` and attaches the payload to the `req.user` object.

4. **Protected Route**:
   - The `/protected` route uses the `authenticateToken` middleware to ensure only authenticated users can access it.

### Client-Side Example

Here is a simple client-side example using fetch:

```html
<!DOCTYPE html>
<html>
<head>
  <title>PASETO Authentication</title>
</head>
<body>
  <h1>PASETO Authentication Example</h1>
  <button id="loginButton">Login</button>
  <button id="protectedButton">Access Protected Route</button>
  <script>
    document.getElementById('loginButton').addEventListener('click', async () => {
      const response = await fetch('http://localhost:3000/login', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({ username: 'admin', password: 'password' })
      });
      const data = await response.json();
      localStorage.setItem('token', data.token);
      alert('Logged in and token stored in local storage');
    });

    document.getElementById('protectedButton').addEventListener('click', async () => {
      const token = localStorage.getItem('token');
      const response = await fetch('http://localhost:3000/protected', {
        method: 'GET',
        headers: {
          'Authorization': `Bearer ${token}`
        }
      });
      const data = await response.json();
      alert(JSON.stringify(data));
    });
  </script>
</body>
</html>
```

### Explanation

1. **Login Button**:
   - Sends a POST request to the `/login` endpoint with the username and password.
   - Stores the received token in `localStorage`.

2. **Protected Button**:
   - Sends a GET request to the `/protected` endpoint with the token in the `Authorization` header.
   - Displays the response data.

This example demonstrates how to use PASETO for token-based authentication in a simple Node.js application with client-side interaction.