<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Nandalal Shukla</title>
    <description>The latest articles on Forem by Nandalal Shukla (@nandalal_shukla_5c06b56be).</description>
    <link>https://forem.com/nandalal_shukla_5c06b56be</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3624272%2F0df97e29-9c04-4c4a-8a19-91b212c3b564.jpg</url>
      <title>Forem: Nandalal Shukla</title>
      <link>https://forem.com/nandalal_shukla_5c06b56be</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/nandalal_shukla_5c06b56be"/>
    <language>en</language>
    <item>
      <title>Creating production-ready authentication and authorization</title>
      <dc:creator>Nandalal Shukla</dc:creator>
      <pubDate>Sat, 22 Nov 2025 11:39:27 +0000</pubDate>
      <link>https://forem.com/nandalal_shukla_5c06b56be/creating-production-ready-authentication-and-authorization-3i27</link>
      <guid>https://forem.com/nandalal_shukla_5c06b56be/creating-production-ready-authentication-and-authorization-3i27</guid>
      <description>&lt;p&gt;Creating production-ready authentication and authorization requires robust security practices. Below is a complete, modular setup for an Express application using JWT, HttpOnly cookies, and role-based access control.&lt;br&gt;
Prerequisites&lt;br&gt;
Project Setup:&lt;br&gt;
bash&lt;br&gt;
mkdir express-auth-api&lt;br&gt;
cd express-auth-api&lt;br&gt;
npm init -y&lt;br&gt;
npm install express jsonwebtoken cookie-parser dotenv&lt;br&gt;
Use code with caution.&lt;/p&gt;

&lt;p&gt;Environment File: Create a .env file in your project root:&lt;br&gt;
env&lt;/p&gt;

&lt;h1&gt;
  
  
  .env
&lt;/h1&gt;

&lt;p&gt;JWT_SECRET=YOUR_VERY_STRONG_RANDOM_SECRET_KEY_HERE&lt;br&gt;
NODE_ENV=development&lt;br&gt;
Use code with caution.&lt;/p&gt;

&lt;p&gt;The Production-Ready Code&lt;br&gt;
This solution is broken down into four files:&lt;br&gt;
server.js: The main application file.&lt;br&gt;
middleware/auth.js: The authentication middleware.&lt;br&gt;
middleware/roleAuth.js: The authorization middleware.&lt;br&gt;
routes/authRoutes.js: Separate routes for login/logout (good practice for larger apps).&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;server.js (Main Application File)
This file sets up the server, connects middleware, and defines protected routes.
javascript
// server.js
const express = require('express');
const cookieParser = require('cookie-parser');
const dotenv = require('dotenv');
const authRoutes = require('./routes/authRoutes');
const authenticateToken = require('./middleware/auth');
const authorizeRole = require('./middleware/roleAuth');&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;dotenv.config();&lt;/p&gt;

&lt;p&gt;const app = express();&lt;br&gt;
const PORT = process.env.PORT || 3000;&lt;br&gt;
const isProduction = process.env.NODE_ENV === 'production';&lt;/p&gt;

&lt;p&gt;// --- Middleware Setup ---&lt;br&gt;
app.use(express.json()); // Allows parsing JSON bodies from POST requests&lt;br&gt;
app.use(cookieParser()); // Allows parsing cookies from incoming requests&lt;/p&gt;

&lt;p&gt;// --- Routes ---&lt;/p&gt;

&lt;p&gt;// Use separate route files for authentication (login/logout)&lt;br&gt;
app.use('/api/auth', authRoutes);&lt;/p&gt;

&lt;p&gt;// Example Public Route&lt;br&gt;
app.get('/api/public', (req, res) =&amp;gt; {&lt;br&gt;
    res.status(200).json({ message: 'This is a public endpoint.' });&lt;br&gt;
});&lt;/p&gt;

&lt;p&gt;// --- Protected Routes (Examples) ---&lt;/p&gt;

&lt;p&gt;// Route accessible by all authenticated users&lt;br&gt;
app.get('/api/profile', authenticateToken, (req, res) =&amp;gt; {&lt;br&gt;
    // req.user contains { id, username, role } thanks to authenticateToken&lt;br&gt;
    res.status(200).json({&lt;br&gt;
        message: &lt;code&gt;Welcome ${req.user.username}, you are authenticated!&lt;/code&gt;,&lt;br&gt;
        user: req.user&lt;br&gt;
    });&lt;br&gt;
});&lt;/p&gt;

&lt;p&gt;// Route accessible only by 'admin' users&lt;br&gt;
app.get('/api/admin-dashboard', authenticateToken, authorizeRole('admin'), (req, res) =&amp;gt; {&lt;br&gt;
    res.status(200).json({&lt;br&gt;
        message: 'Welcome to the Admin Dashboard, only visible to Admins!'&lt;br&gt;
    });&lt;br&gt;
});&lt;/p&gt;

&lt;p&gt;// Route accessible only by 'user' role&lt;br&gt;
app.get('/api/user-dashboard', authenticateToken, authorizeRole('user'), (req, res) =&amp;gt; {&lt;br&gt;
    res.status(200).json({&lt;br&gt;
        message: 'Welcome to the User Dashboard.'&lt;br&gt;
    });&lt;br&gt;
});&lt;/p&gt;

&lt;p&gt;// --- Server Start ---&lt;br&gt;
app.listen(PORT, () =&amp;gt; {&lt;br&gt;
    console.log(&lt;code&gt;Server running on http://localhost:${PORT}&lt;/code&gt;);&lt;br&gt;
});&lt;br&gt;
Use code with caution.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;middleware/auth.js (Authentication Middleware)
This middleware verifies the JWT and attaches the decoded user data to the request object.
javascript
// middleware/auth.js
const jwt = require('jsonwebtoken');&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;function authenticateToken(req, res, next) {&lt;br&gt;
    // 1. Extract the token from the HttpOnly cookie&lt;br&gt;
    const token = req.cookies &amp;amp;&amp;amp; req.cookies.accessToken;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if (token == null) {
    // If no token exists in the cookie, the user is not authenticated.
    return res.status(401).json({ message: 'Authentication required. No token provided.' });
}

// 2. Verify the token's signature using the secret key
jwt.verify(token, process.env.JWT_SECRET, (err, user) =&amp;gt; {
    if (err) {
        // If the token is invalid (expired, manipulated, etc.)
        return res.status(403).json({ message: 'Forbidden. Invalid or expired token.' });
    }

    // 3. If valid, attach the decoded user payload ({ id, username, role }) to the request
    req.user = user;

    // 4. Pass control to the next middleware or route handler
    next();
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;}&lt;/p&gt;

&lt;p&gt;module.exports = authenticateToken;&lt;br&gt;
Use code with caution.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;middleware/roleAuth.js (Authorization Middleware)
This middleware uses the req.user data provided by authenticateToken to check for specific roles.
javascript
// middleware/roleAuth.js&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;/**&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Factory function to create authorization middleware for a specific required role.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="mentioned-user" href="https://dev.to/param"&gt;@param&lt;/a&gt; {string} requiredRole - The role needed for access (e.g., 'admin', 'user')&lt;br&gt;
*/&lt;br&gt;
function authorizeRole(requiredRole) {&lt;br&gt;
return (req, res, next) =&amp;gt; {&lt;br&gt;
    // We assume req.user has been populated by the authenticateToken middleware&lt;br&gt;
    if (!req.user || req.user.role !== requiredRole) {&lt;br&gt;
        return res.status(403).json({ &lt;br&gt;
            message: &lt;code&gt;Access denied. You do not have the required role: ${requiredRole}.&lt;/code&gt; &lt;br&gt;
        });&lt;br&gt;
    }&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Role matches, proceed to the next handler
next();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;};&lt;br&gt;
}&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;module.exports = authorizeRole;&lt;br&gt;
Use code with caution.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;routes/authRoutes.js (Login/Logout Logic)
Separating auth logic keeps your main server file clean.
javascript
// routes/authRoutes.js
const express = require('express');
const jwt = require('jsonwebtoken');
const router = express.Router();&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;// Mock database of users (replace with a real DB query in production)&lt;br&gt;
const mockUsersDb = [&lt;br&gt;
    { id: 1, username: 'user', role: 'user', passwordHash: 'password123' },&lt;br&gt;
    { id: 2, username: 'admin', role: 'admin', passwordHash: 'adminpass' }&lt;br&gt;
];&lt;/p&gt;

&lt;p&gt;const isProduction = process.env.NODE_ENV === 'production';&lt;/p&gt;

&lt;p&gt;// --- Login Route ---&lt;br&gt;
router.post('/login', (req, res) =&amp;gt; {&lt;br&gt;
    const { username, password } = req.body;&lt;br&gt;
    const user = mockUsersDb.find(u =&amp;gt; u.username === username);&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// In a production app, use bcrypt to compare password hashes
if (!user || user.passwordHash !== password) {
    return res.status(401).json({ message: 'Invalid credentials' });
}

// Payload includes necessary claims, crucially the 'role'
const payload = { id: user.id, username: user.username, role: user.role };
const accessToken = jwt.sign(payload, process.env.JWT_SECRET, { expiresIn: '1h' });

// Set the HttpOnly cookie for secure storage
res.cookie('accessToken', accessToken, {
    httpOnly: true, // Prevents client-side JS access (XSS mitigation)
    secure: isProduction, // Ensures cookie is sent only over HTTPS in production
    sameSite: 'Strict', // Mitigates CSRF
    maxAge: 3600000 // 1 hour expiration
});

res.status(200).json({ message: 'Login successful', role: user.role });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;});&lt;/p&gt;

&lt;p&gt;// --- Logout Route ---&lt;br&gt;
router.post('/logout', (req, res) =&amp;gt; {&lt;br&gt;
    res.clearCookie('accessToken', {&lt;br&gt;
        httpOnly: true,&lt;br&gt;
        secure: isProduction,&lt;br&gt;
        sameSite: 'Strict',&lt;br&gt;
    });&lt;br&gt;
    res.status(200).json({ message: 'Logged out successfully' });&lt;br&gt;
});&lt;/p&gt;

&lt;p&gt;module.exports = router;&lt;br&gt;
Use code with caution.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>security</category>
      <category>node</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
