Refresh Tokens (JWT + Refresh token system) Two-Factor Authentication (2FA) via OTP Role-Based Access Control (RBAC) Swagger API Documentation

 

Enhancements We'll Add

  1. Refresh Tokens (JWT + Refresh token system)

  2. Two-Factor Authentication (2FA) via OTP

  3. Role-Based Access Control (RBAC)

  4. Swagger API Documentation

  5. Unit Testing with Jest


Let’s break this down step-by-step. I’ll guide you through each feature and include code examples where possible.


1. Refresh Tokens

Why?
Access tokens expire quickly. Refresh tokens allow re-authentication without logging in again.


Step 1: Update User Schema

js

refreshToken: { type: String }

Step 2: Generate Refresh Token

js

const generateRefreshToken = (userId) => { return jwt.sign({ id: userId }, process.env.JWT_REFRESH_SECRET, { expiresIn: '7d' }); };

Step 3: Login Endpoint (Update)

js

const accessToken = generateToken(user._id); const refreshToken = generateRefreshToken(user._id); user.refreshToken = refreshToken; await user.save(); res.json({ accessToken, refreshToken });

Step 4: Refresh Endpoint

js

router.post('/refresh', async (req, res) => { const { refreshToken } = req.body; if (!refreshToken) return res.status(401).json({ message: "No token" }); try { const decoded = jwt.verify(refreshToken, process.env.JWT_REFRESH_SECRET); const user = await User.findById(decoded.id); if (user.refreshToken !== refreshToken) throw new Error(); const newAccessToken = generateToken(user._id); res.json({ accessToken: newAccessToken }); } catch { res.status(401).json({ message: "Invalid refresh token" }); } });

2. Two-Factor Authentication (2FA with OTP)

Use speakeasy for OTP generation and qrcode for QR display.

bash

npm install speakeasy qrcode

Step 1: Enable 2FA in User Model

js

twoFactorEnabled: { type: Boolean, default: false }, twoFactorSecret: String,

Step 2: Setup 2FA Endpoint

js

const speakeasy = require('speakeasy'); const qrcode = require('qrcode'); router.get('/2fa/setup', protect, async (req, res) => { const secret = speakeasy.generateSecret({ name: 'SecureAPI' }); const user = await User.findById(req.user); user.twoFactorSecret = secret.base32; await user.save(); const qr = await qrcode.toDataURL(secret.otpauth_url); res.json({ qr }); });

Step 3: Verify OTP on Login

js

if (user.twoFactorEnabled) { if (!otp) return res.status(400).json({ message: "OTP required" }); const verified = speakeasy.totp.verify({ secret: user.twoFactorSecret, encoding: 'base32', token: otp }); if (!verified) return res.status(400).json({ message: "Invalid OTP" }); }

3. Role-Based Access Control (RBAC)


Step 1: Add Role to User

js

role: { type: String, enum: ['user', 'admin'], default: 'user' }

Step 2: Role Middleware

js

const checkRole = (...roles) => (req, res, next) => { if (!roles.includes(req.user.role)) return res.status(403).json({ message: 'Forbidden' }); next(); };

Usage:

js

router.get('/admin', protect, checkRole('admin'), adminController);

4. Swagger Documentation

bash

npm install swagger-ui-express swagger-jsdoc

app.js

js

const swaggerUi = require('swagger-ui-express'); const swaggerJsDoc = require('swagger-jsdoc'); const swaggerSpec = swaggerJsDoc({ swaggerDefinition: { openapi: '3.0.0', info: { title: 'Secure API', version: '1.0.0', }, servers: [{ url: 'http://localhost:5000/api' }] }, apis: ['./routes/*.js'] }); app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec));

Sample Swagger Comment in Route

js

/** * @swagger * /auth/login: * post: * summary: Login user * tags: [Auth] * requestBody: * required: true * responses: * 200: * description: Success */

5. Unit Testing with Jest

bash

npm install --save-dev jest supertest

Basic Test Example: /tests/auth.test

const request = require('supertest'); const app = require('../app'); describe('Auth routes', () => { it('should register a user', async () => { const res = await request(app).post('/api/auth/register') .send({ email: 'test@example.com', password: 'password' }); expect(res.statusCode).toEqual(201); expect(res.body).toHaveProperty('token'); }); });

Update package.json for testing

json

"scripts": { "test": "jest" }


No comments:

Post a Comment

latest ECMAScript proposals and releases (as of ECMAScript 2024), several enhancements have been made to built-in objects like Set

JavaScript continues to evolve, and in the latest ECMAScript proposals and releases (as of ECMAScript 2024), several enhancements have been ...

Best for you