🌐 Detecting your location…
📢 Advertisement — Configure AdSense in Appearance → Customize → AdSense Settings

Express.js में JWT प्रमाणीकरण कैसे लागू करें: चरण-दर-चरण 2026 मार्गदर्शिका

⏱️4 min read  ·  692 words

JWT (JSON वेब टोकन) प्रमाणीकरण Node.js अनुप्रयोगों में REST API को सुरक्षित करने के लिए मानक है। 2026 में, कार्यान्वयन पैटर्न अच्छी तरह से स्थापित हैं – लेकिन कई ट्यूटोरियल ताज़ा टोकन रोटेशन, उचित गुप्त प्रबंधन और टोकन अमान्यकरण जैसे महत्वपूर्ण सुरक्षा विवरणों को छोड़ देते हैं। यह मार्गदर्शिका संपूर्ण, उत्पादन-तैयार कार्यान्वयन को कवर करती है।

JWT प्रमाणीकरण कैसे काम करता है

  1. उपयोगकर्ता क्रेडेंशियल के साथ लॉग इन करता है → सर्वर उन्हें सत्यापित करता है
  2. सर्वर दो टोकन जारी करता है:एक्सेस टोकन (अल्पकालिक, 15 मिनट) औरताज़ा टोकन (दीर्घायु, 7 दिन)
  3. क्लाइंट प्रत्येक अनुरोध के लिए प्राधिकरण शीर्षलेख में एक्सेस टोकन भेजता है
  4. जब एक्सेस टोकन समाप्त हो जाता है, तो क्लाइंट नया एक्सेस टोकन प्राप्त करने के लिए रीफ्रेश टोकन भेजता है
  5. लॉगआउट पर, ताज़ा टोकन सर्वर-साइड अमान्य है

सेटअप

npm install express jsonwebtoken bcryptjs cookie-parser ioredis
npm install -D @types/jsonwebtoken @types/bcryptjs

टोकन सेवा

// services/tokenService.js
const jwt = require('jsonwebtoken');
const Redis = require('ioredis');

const redis = new Redis(process.env.REDIS_URL);

const ACCESS_SECRET  = process.env.JWT_ACCESS_SECRET;
const REFRESH_SECRET = process.env.JWT_REFRESH_SECRET;
// CRITICAL: Use different secrets for access and refresh tokens

function generateAccessToken(payload) {
  return jwt.sign(payload, ACCESS_SECRET, {
    expiresIn:  '15m',
    issuer:     'myapp',
    audience:   'myapp-users',
  });
}

function generateRefreshToken(payload) {
  return jwt.sign(payload, REFRESH_SECRET, {
    expiresIn: '7d',
    issuer:    'myapp',
    audience:  'myapp-users',
    jwtid:     crypto.randomUUID(),  // unique ID for invalidation
  });
}

function verifyAccessToken(token) {
  return jwt.verify(token, ACCESS_SECRET, {
    issuer:   'myapp',
    audience: 'myapp-users',
  });
}

async function verifyRefreshToken(token) {
  const payload = jwt.verify(token, REFRESH_SECRET, {
    issuer:   'myapp',
    audience: 'myapp-users',
  });
  // Check token hasn't been revoked
  const isRevoked = await redis.get(`revoked:${payload.jti}`);
  if (isRevoked) throw new Error('Token revoked');
  return payload;
}

async function revokeRefreshToken(token) {
  try {
    const payload = jwt.decode(token);
    if (payload?.jti && payload?.exp) {
      const ttl = payload.exp - Math.floor(Date.now() / 1000);
      if (ttl > 0) {
        await redis.setex(`revoked:${payload.jti}`, ttl, '1');
      }
    }
  } catch (err) {
    // Ignore decode errors on logout
  }
}

module.exports = {
  generateAccessToken, generateRefreshToken,
  verifyAccessToken, verifyRefreshToken, revokeRefreshToken
};

प्रमाणीकरण मार्ग

// routes/auth.js
const express = require('express');
const bcrypt  = require('bcryptjs');
const router  = express.Router();
const { generateAccessToken, generateRefreshToken,
        verifyRefreshToken, revokeRefreshToken } = require('../services/tokenService');
const { findUserByEmail } = require('../db/users');

// POST /auth/login
router.post('/login', async (req, res) => {
  const { email, password } = req.body;

  if (!email || !password) {
    return res.status(400).json({ error: 'Email and password required' });
  }

  const user = await findUserByEmail(email);
  if (!user || !(await bcrypt.compare(password, user.hashedPassword))) {
    // Same error for missing user and wrong password (prevent user enumeration)
    return res.status(401).json({ error: 'Invalid credentials' });
  }

  const payload = { sub: user.id, email: user.email, role: user.role };
  const accessToken  = generateAccessToken(payload);
  const refreshToken = generateRefreshToken(payload);

  // Store refresh token in httpOnly cookie (not accessible to JS)
  res.cookie('refreshToken', refreshToken, {
    httpOnly: true,
    secure:   process.env.NODE_ENV === 'production',
    sameSite: 'strict',
    maxAge:   7 * 24 * 60 * 60 * 1000,  // 7 days in ms
  });

  res.json({ accessToken, user: { id: user.id, email: user.email, role: user.role } });
});

// POST /auth/refresh
router.post('/refresh', async (req, res) => {
  const refreshToken = req.cookies.refreshToken;
  if (!refreshToken) return res.status(401).json({ error: 'No refresh token' });

  try {
    const payload = await verifyRefreshToken(refreshToken);

    // Refresh token rotation: revoke old, issue new
    await revokeRefreshToken(refreshToken);
    const newRefreshToken = generateRefreshToken({
      sub: payload.sub, email: payload.email, role: payload.role
    });
    const newAccessToken = generateAccessToken({
      sub: payload.sub, email: payload.email, role: payload.role
    });

    res.cookie('refreshToken', newRefreshToken, {
      httpOnly: true,
      secure:   process.env.NODE_ENV === 'production',
      sameSite: 'strict',
      maxAge:   7 * 24 * 60 * 60 * 1000,
    });
    res.json({ accessToken: newAccessToken });
  } catch (err) {
    res.clearCookie('refreshToken');
    res.status(401).json({ error: 'Invalid or expired refresh token' });
  }
});

// POST /auth/logout
router.post('/logout', async (req, res) => {
  const refreshToken = req.cookies.refreshToken;
  if (refreshToken) await revokeRefreshToken(refreshToken);
  res.clearCookie('refreshToken');
  res.json({ message: 'Logged out successfully' });
});

module.exports = router;

प्रमाणीकरण मिडलवेयर

// middleware/authenticate.js
const { verifyAccessToken } = require('../services/tokenService');

function authenticate(req, res, next) {
  const authHeader = req.headers.authorization;
  if (!authHeader?.startsWith('Bearer ')) {
    return res.status(401).json({ error: 'Access token required' });
  }

  const token = authHeader.split(' ')[1];
  try {
    const payload = verifyAccessToken(token);
    req.user = payload;  // { sub, email, role, iat, exp }
    next();
  } catch (err) {
    if (err.name === 'TokenExpiredError') {
      return res.status(401).json({ error: 'Access token expired', code: 'TOKEN_EXPIRED' });
    }
    res.status(401).json({ error: 'Invalid access token' });
  }
}

// Role-based authorization
function authorize(...roles) {
  return (req, res, next) => {
    if (!roles.includes(req.user?.role)) {
      return res.status(403).json({ error: 'Insufficient permissions' });
    }
    next();
  };
}

module.exports = { authenticate, authorize };

मार्गों की सुरक्षा

const { authenticate, authorize } = require('./middleware/authenticate');

// Public route
app.get('/health', (req, res) => res.json({ status: 'ok' }));

// Authenticated route
app.get('/api/profile', authenticate, (req, res) => {
  res.json({ userId: req.user.sub, email: req.user.email });
});

// Role-restricted route
app.delete('/api/users/:id', authenticate, authorize('admin'), async (req, res) => {
  await deleteUser(req.params.id);
  res.json({ deleted: true });
});

महत्वपूर्ण सुरक्षा जाँच सूची

  • लोकलस्टोरेज में कभी भी टोकन स्टोर न करें – XSS के प्रति संवेदनशील। टोकन ताज़ा करने के लिए httpOnly कुकीज़ का उपयोग करें।
  • अलग रहस्यों का प्रयोग करें टोकन तक पहुंच और ताज़ा करने के लिए। यदि एक्सेस गुप्त लीक हो जाता है, तो ताज़ा टोकन सुरक्षित रहते हैं।
  • शॉर्ट एक्सेस टोकन समाप्ति (अधिकतम 15 मिनट)। लंबे समय तक चलने वाले एक्सेस टोकन को अस्वीकृत सूची के बिना अमान्य नहीं किया जा सकता है।
  • ताज़ा टोकन रोटेशन – प्रत्येक रिफ्रेश एक नया रिफ्रेश टोकन जारी करता है और पुराने को निरस्त कर देता है। टोकन चोरी का पता लगाता है।
  • केवल HTTPS उत्पादन में – पारगमन में JWTs को एन्क्रिप्ट किया जाना चाहिए।
  • आईएस और ऑड दावों को मान्य करें – एक सेवा के टोकन को दूसरी सेवा में उपयोग करने से रोकता है।

अक्सर पूछे जाने वाले प्रश्न

प्रश्न: सेशंस बनाम जेडब्ल्यूटी – कौन सा बेहतर है?
उ: सत्र (सर्वर-साइड स्थिति) को तुरंत अमान्य करना आसान है। जेडब्ल्यूटी स्टेटलेस हैं और साझा सत्र स्टोर के बिना क्षैतिज रूप से स्केल करते हैं। सरल ऐप्स के लिए सत्र का उपयोग करें; मोबाइल/एसपीए क्लाइंट या माइक्रोसर्विसेज द्वारा उपभोग किए जाने वाले एपीआई के लिए जेडब्ल्यूटी।

प्रश्न: मैं समाप्ति से पहले JWT को कैसे अमान्य कर सकता हूँ?
ए: दो दृष्टिकोण: (1) निरस्त टोकन जेटीआई की रेडिस अस्वीकृत सूची बनाए रखें – हर अनुरोध पर जाँच की जाती है। (2) एक्सेस टोकन समाप्ति को छोटा करें ताकि क्षति विंडो छोटी हो। विकल्प 1 अधिक सुरक्षित है; विकल्प 2 सरल है.

प्रश्न: क्लाइंट पर एक्सेस टोकन कहाँ संग्रहीत किया जाना चाहिए?
ए: मेमोरी में (जावास्क्रिप्ट वैरिएबल) – लोकलस्टोरेज या सेशनस्टोरेज नहीं। मेमोरी स्टोरेज का मतलब है कि यह पेज रीफ्रेश पर खो गया है, नया प्राप्त करने के लिए रीफ्रेश टोकन कॉल की आवश्यकता होती है – यही इच्छित व्यवहार है।

प्रश्न: क्या मुझे आरएस256 या एचएस256 का उपयोग करना चाहिए?
उत्तर: उन सेवाओं के लिए HS256 (सममित, साझा रहस्य) जिन्हें आप पूरी तरह से नियंत्रित करते हैं। RS256 (असममित, सार्वजनिक/निजी कुंजी) जब तीसरे पक्ष को आपके रहस्य को जाने बिना टोकन सत्यापित करने की आवश्यकता होती है – जैसे कि माइक्रोसर्विसेज या पार्टनर।

प्रश्न: मैं फ्रंटएंड पर “टोकन समाप्त हो गया” को कैसे संभालूं?
ए:code: "TOKEN_EXPIRED"के साथ 401 प्रतिक्रियाओं को अवरोधित करें हेडर, स्वचालित रूप से कॉल/auth/refresh, एक नया एक्सेस टोकन प्राप्त करें, और मूल अनुरोध पुनः प्रयास करें। अधिकांश HTTP क्लाइंट (axios, ky) इस पैटर्न के लिए अनुरोध इंटरसेप्टर का समर्थन करते हैं।

निष्कर्ष

उत्पादन JWT प्रमाणीकरण के लिए केवलjwt.sign()से अधिक की आवश्यकता होती है औरjwt.verify(). पूर्ण कार्यान्वयन में शामिल हैं: ताज़ा टोकन के लिए httpकेवल कुकीज़, हर ताज़ा पर टोकन रोटेशन, लॉगआउट के लिए रेडिस-समर्थित निरस्तीकरण, प्रत्येक टोकन प्रकार के लिए अलग रहस्य, और भूमिका-आधारित प्राधिकरण मिडलवेयर। यह आर्किटेक्चर क्षैतिज रूप से स्केल करता है (स्टेटलेस एक्सेस टोकन), टोकन चोरी को संभालता है (रोटेशन पुन: उपयोग का पता लगाता है), और उचित लॉगआउट (निरस्तीकरण सूची) का समर्थन करता है। इस फाउंडेशन से शुरुआत करें और आपको बाद में अपने प्रमाणीकरण सिस्टम को दोबारा बनाने की आवश्यकता नहीं होगी।

✍️ Leave a Comment

Your email address will not be published. Required fields are marked *

🌐 Read in:🇩🇪 Deutsch🇧🇷 Português🇸🇦 العربية🇮🇳 हिन्दी🇧🇩 বাংলা