Node.
js Complete Guide
Part 7: Authentication and Security
Building Secure Applications
Part 7 of 10-Part Series
Security is paramount in modern web applications. In this part, we'll explore comprehensive authentication and
security practices for [Link] applications. You'll learn password hashing, JWT authentication, session
management, OAuth integration, role-based access control, and essential security measures to protect your
applications from common vulnerabilities.
1. Password Security
1.1 Password Hashing with bcrypt
npm install bcryptjs
// utils/[Link]
const bcrypt = require('bcryptjs');
async function hashPassword(password) {
const saltRounds = 12;
return await [Link](password, saltRounds);
}
async function comparePassword(plainPassword, hashedPassword) {
return await [Link](plainPassword, hashedPassword);
}
[Link] = { hashPassword, comparePassword };
1.2 Password Validation
function validatePassword(password) {
const errors = [];
if ([Link] < 8) {
[Link]('Password must be at least 8 characters');
}
if ([Link] > 128) {
[Link]('Password must not exceed 128 characters');
}
if (!/[A-Z]/.test(password)) {
[Link]('Must contain uppercase letter');
}
if (!/[a-z]/.test(password)) {
[Link]('Must contain lowercase letter');
}
if (!/[0-9]/.test(password)) {
[Link]('Must contain number');
}
if (!/[!@#$%^&*]/.test(password)) {
[Link]('Must contain special character');
}
const commonPasswords = ['password', '12345678', 'qwerty'];
if ([Link]([Link]())) {
[Link]('Password is too common');
}
return { isValid: [Link] === 0, errors };
}
2. JWT Authentication
2.1 JWT Setup
npm install jsonwebtoken
// config/[Link]
const jwt = require('jsonwebtoken');
const JWT_SECRET = [Link].JWT_SECRET;
const JWT_EXPIRE = '7d';
const JWT_REFRESH_SECRET = [Link].JWT_REFRESH_SECRET;
function generateAccessToken(userId, role) {
return [Link]({ userId, role, type: 'access' }, JWT_SECRET,
{ expiresIn: JWT_EXPIRE });
}
function generateRefreshToken(userId) {
return [Link]({ userId, type: 'refresh' }, JWT_REFRESH_SECRET,
{ expiresIn: '30d' });
}
function verifyAccessToken(token) {
try {
const decoded = [Link](token, JWT_SECRET);
return { valid: true, decoded };
} catch (error) {
return { valid: false, error: [Link] };
}
}
[Link] = { generateAccessToken, generateRefreshToken, verifyAccessToken };
2.2 Authentication Middleware
// middleware/[Link]
const { verifyAccessToken } = require('../config/jwt');
const User = require('../models/User');
const authenticate = async (req, res, next) => {
try {
const authHeader = [Link];
if (!authHeader || ) {
return [Link](401).json({ error: 'No token provided' });
}
const token = [Link](' ')[1];
const { valid, decoded } = verifyAccessToken(token);
if (!valid) {
return [Link](401).json({ error: 'Invalid token' });
}
const user = await [Link]([Link]).select('-password');
if (!user || ![Link]) {
return [Link](401).json({ error: 'User not found or inactive' });
}
[Link] = user;
[Link] = [Link];
next();
} catch (error) {
[Link](500).json({ error: 'Authentication failed' });
}
};
[Link] = { authenticate };
2.3 Login and Registration
// controllers/[Link]
const User = require('../models/User');
const { hashPassword, comparePassword } = require('../utils/password');
const { generateAccessToken, generateRefreshToken } = require('../config/jwt');
[Link] = async (req, res) => {
try {
const { name, email, password } = [Link];
if (!name || !email || !password) {
return [Link](400).json({ error: 'All fields required' });
}
const existingUser = await [Link]({ email });
if (existingUser) {
return [Link](400).json({ error: 'Email already registered' });
}
const hashedPassword = await hashPassword(password);
const user = await [Link]({ name, email, password: hashedPassword });
const accessToken = generateAccessToken(user._id, [Link]);
const refreshToken = generateRefreshToken(user._id);
[Link](201).json({
status: 'success',
data: {
user: { id: user._id, name: [Link], email: [Link] },
accessToken,
refreshToken
}
});
} catch (error) {
[Link](500).json({ error: [Link] });
}
};
[Link] = async (req, res) => {
try {
const { email, password } = [Link];
const user = await [Link]({ email }).select('+password');
if (!user) {
return [Link](401).json({ error: 'Invalid credentials' });
}
if (![Link]) {
return [Link](401).json({ error: 'Account disabled' });
}
const isValid = await comparePassword(password, [Link]);
if (!isValid) {
return [Link](401).json({ error: 'Invalid credentials' });
}
const accessToken = generateAccessToken(user._id, [Link]);
const refreshToken = generateRefreshToken(user._id);
[Link] = new Date();
await [Link]();
[Link]({
status: 'success',
data: {
user: { id: user._id, name: [Link], email: [Link] },
accessToken,
refreshToken
}
});
} catch (error) {
[Link](500).json({ error: [Link] });
}
};
3. Role-Based Access Control
3.1 Authorization Middleware
// middleware/[Link]
const authorize = (...allowedRoles) => {
return (req, res, next) => {
if (![Link]) {
return [Link](401).json({ error: 'Authentication required' });
}
if () {
return [Link](403).json({
error: 'You do not have permission to perform this action'
});
}
next();
};
};
const authorizeOwner = (resourceModel, resourceParam = 'id') => {
return async (req, res, next) => {
try {
const resourceId = [Link][resourceParam];
const resource = await [Link](resourceId);
if (!resource) {
return [Link](404).json({ error: 'Resource not found' });
}
const isOwner = [Link]?.toString() === [Link];
const isAdmin = [Link] === 'admin';
if (!isOwner && !isAdmin) {
return [Link](403).json({ error: 'Access denied' });
}
[Link] = resource;
next();
} catch (error) {
[Link](500).json({ error: [Link] });
}
};
};
[Link] = { authorize, authorizeOwner };
3.2 Using Authorization
const { authenticate } = require('../middleware/auth');
const { authorize, authorizeOwner } = require('../middleware/authorize');
const Post = require('../models/Post');
// Admin only
[Link]('/admin/dashboard',
authenticate,
authorize('admin'),
(req, res) => {
[Link]({ message: 'Admin dashboard' });
}
);
// Admin or moderator
[Link]('/moderation',
authenticate,
authorize('admin', 'moderator'),
(req, res) => {
[Link]({ message: 'Moderation panel' });
}
);
// Owner or admin can update
[Link]('/posts/:id',
authenticate,
authorizeOwner(Post, 'id'),
async (req, res) => {
const post = [Link];
[Link] = [Link] || [Link];
await [Link]();
[Link]({ data: post });
}
);
4. Security Best Practices
4.1 Essential Security Middleware
npm install helmet cors express-rate-limit express-mongo-sanitize xss-clean hpp
// [Link]
const express = require('express');
const helmet = require('helmet');
const cors = require('cors');
const rateLimit = require('express-rate-limit');
const mongoSanitize = require('express-mongo-sanitize');
const xss = require('xss-clean');
const hpp = require('hpp');
const app = express();
// 1. Helmet - Security headers
[Link](helmet());
// 2. CORS - Control cross-origin requests
[Link](cors({
origin: [Link].ALLOWED_ORIGINS?.split(',') || '[Link]
credentials: true,
maxAge: 86400
}));
// 3. Rate limiting
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // 100 requests per window
message: 'Too many requests, please try again later'
});
[Link]('/api', limiter);
// Stricter for auth routes
const authLimiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 5,
message: 'Too many login attempts'
});
[Link]('/api/auth/login', authLimiter);
// 4. Body parsing with size limits
[Link]([Link]({ limit: '10kb' }));
[Link]([Link]({ extended: true, limit: '10kb' }));
// 5. Data sanitization - NoSQL injection
[Link](mongoSanitize());
// 6. Data sanitization - XSS
[Link](xss());
// 7. Prevent parameter pollution
[Link](hpp({
whitelist: ['price', 'rating'] // Allow duplicates for these params
}));
4.2 HTTPS and Secure Cookies
// Production HTTPS configuration
const https = require('https');
const fs = require('fs');
if ([Link].NODE_ENV === 'production') {
const options = {
key: [Link]('/path/to/[Link]'),
cert: [Link]('/path/to/[Link]')
};
[Link](options, app).listen(443, () => {
[Link]('HTTPS server running on port 443');
});
} else {
[Link](3000);
}
// Secure cookie settings
[Link]('/login', (req, res) => {
const token = generateToken(user._id);
[Link]('token', token, {
httpOnly: true, // Prevent XSS
secure: [Link].NODE_ENV === 'production', // HTTPS only
sameSite: 'strict', // CSRF protection
maxAge: 7 * 24 * 60 * 60 * 1000 // 7 days
});
[Link]({ status: 'success' });
});
4.3 CSRF Protection
npm install csurf
const csrf = require('csurf');
const csrfProtection = csrf({ cookie: true });
// Apply CSRF protection to state-changing routes
[Link]('/api/data', csrfProtection, (req, res) => {
[Link]({ data: 'protected' });
});
// Send CSRF token to client
[Link]('/api/csrf-token', csrfProtection, (req, res) => {
[Link]({ csrfToken: [Link]() });
});
// Client must include token in requests:
// Headers: { 'CSRF-Token': csrfToken }
// Or in body: { _csrf: csrfToken }
4.4 Input Validation and Sanitization
npm install express-validator
const { body, validationResult } = require('express-validator');
// Validation middleware
const validateUser = [
body('email')
.trim()
.isEmail().withMessage('Invalid email')
.normalizeEmail(),
body('name')
.trim()
.isLength({ min: 2, max: 50 })
.withMessage('Name must be 2-50 characters')
.escape(), // Sanitize HTML
body('age')
.optional()
.isInt({ min: 0, max: 150 })
.withMessage('Age must be 0-150')
];
[Link]('/users', validateUser, (req, res) => {
const errors = validationResult(req);
if (![Link]()) {
return [Link](400).json({ errors: [Link]() });
}
// Process validated data
[Link]({ status: 'success' });
});
5. OAuth 2.0 Integration
5.1 OAuth with [Link]
npm install passport passport-google-oauth20 passport-github2
// config/[Link]
const passport = require('passport');
const GoogleStrategy = require('passport-google-oauth20').Strategy;
const User = require('../models/User');
[Link](new GoogleStrategy({
clientID: [Link].GOOGLE_CLIENT_ID,
clientSecret: [Link].GOOGLE_CLIENT_SECRET,
callbackURL: '/auth/google/callback'
},
async (accessToken, refreshToken, profile, done) => {
try {
let user = await [Link]({ googleId: [Link] });
if (!user) {
user = await [Link]({
googleId: [Link],
name: [Link],
email: [Link][0].value,
avatar: [Link][0].value,
provider: 'google'
});
}
done(null, user);
} catch (error) {
done(error, null);
}
}
));
[Link] = passport;
5.2 OAuth Routes
// routes/[Link]
const passport = require('../config/passport');
const { generateAccessToken } = require('../config/jwt');
// Initiate Google OAuth
[Link]('/google',
[Link]('google', { scope: ['profile', 'email'] })
);
// Google callback
[Link]('/google/callback',
[Link]('google', {
failureRedirect: '/login',
session: false
}),
(req, res) => {
const token = generateAccessToken([Link]._id, [Link]);
[Link](`${[Link].CLIENT_URL}/auth/success?token=${token}`);
}
);
6. Advanced Security Topics
6.1 Two-Factor Authentication (2FA)
npm install speakeasy qrcode
const speakeasy = require('speakeasy');
const QRCode = require('qrcode');
// Enable 2FA for user
exports.enable2FA = async (req, res) => {
try {
const user = await [Link]([Link]);
// Generate secret
const secret = [Link]({
name: `MyApp (${[Link]})`
});
// Store secret temporarily
[Link] = secret.base32;
await [Link]();
// Generate QR code
const qrCodeUrl = await [Link](secret.otpauth_url);
[Link]({
status: 'success',
data: {
secret: secret.base32,
qrCode: qrCodeUrl
}
});
} catch (error) {
[Link](500).json({ error: [Link] });
}
};
// Verify and activate 2FA
exports.verify2FA = async (req, res) => {
try {
const { token } = [Link];
const user = await [Link]([Link]);
const verified = [Link]({
secret: [Link],
encoding: 'base32',
token: token
});
if (!verified) {
return [Link](400).json({ error: 'Invalid token' });
}
// Activate 2FA
[Link] = [Link];
[Link] = true;
[Link] = undefined;
await [Link]();
[Link]({ status: 'success', message: '2FA enabled' });
} catch (error) {
[Link](500).json({ error: [Link] });
}
};
// Login with 2FA
exports.loginWith2FA = async (req, res) => {
const { email, password, token } = [Link];
const user = await [Link]({ email }).select('+password');
// Verify password first
const isPasswordValid = await comparePassword(password, [Link]);
if (!isPasswordValid) {
return [Link](401).json({ error: 'Invalid credentials' });
}
// Check if 2FA is enabled
if ([Link]) {
if (!token) {
return [Link](403).json({
error: '2FA required',
requires2FA: true
});
}
const verified = [Link]({
secret: [Link],
encoding: 'base32',
token: token
});
if (!verified) {
return [Link](401).json({ error: 'Invalid 2FA token' });
}
}
// Generate JWT
const accessToken = generateAccessToken(user._id, [Link]);
[Link]({ status: 'success', accessToken });
};
6.2 API Key Authentication
// Generate API key
const crypto = require('crypto');
function generateApiKey() {
return [Link](32).toString('hex');
}
// Store API keys in database
const apiKeySchema = new [Link]({
key: {
type: String,
required: true,
unique: true,
index: true
},
userId: {
type: [Link],
ref: 'User',
required: true
},
name: String,
permissions: [String],
expiresAt: Date,
lastUsedAt: Date,
isActive: {
type: Boolean,
default: true
}
}, { timestamps: true });
// Create API key
[Link] = async (req, res) => {
try {
const { name, permissions } = [Link];
const key = generateApiKey();
const apiKey = await [Link]({
key,
userId: [Link],
name,
permissions
});
[Link](201).json({
status: 'success',
data: {
key: [Link],
name: [Link]
}
});
} catch (error) {
[Link](500).json({ error: [Link] });
}
};
// API key authentication middleware
const authenticateApiKey = async (req, res, next) => {
try {
const apiKey = [Link]['x-api-key'];
if (!apiKey) {
return [Link](401).json({ error: 'API key required' });
}
const key = await [Link]({
key: apiKey,
isActive: true
}).populate('userId');
if (!key) {
return [Link](401).json({ error: 'Invalid API key' });
}
// Check expiration
if ([Link] && [Link] < new Date()) {
return [Link](401).json({ error: 'API key expired' });
}
// Update last used
[Link] = new Date();
await [Link]();
[Link] = [Link];
[Link] = key;
next();
} catch (error) {
[Link](500).json({ error: 'Authentication failed' });
}
};
// Usage
[Link]('/api/data', authenticateApiKey, (req, res) => {
[Link]({ data: 'protected data' });
});
6.3 Audit Logging
// models/[Link]
const auditLogSchema = new [Link]({
userId: {
type: [Link],
ref: 'User'
},
action: {
type: String,
required: true,
enum: ['create', 'read', 'update', 'delete', 'login', 'logout']
},
resource: String,
resourceId: [Link],
ip: String,
userAgent: String,
details: [Link],
timestamp: {
type: Date,
default: [Link]
}
});
const AuditLog = [Link]('AuditLog', auditLogSchema);
// Audit middleware
const audit = (action, resource) => {
return async (req, res, next) => {
const originalJson = [Link](res);
[Link] = function(data) {
// Log after successful response
[Link]({
userId: [Link],
action,
resource,
resourceId: [Link],
ip: [Link],
userAgent: [Link]('user-agent'),
details: {
method: [Link],
url: [Link],
body: [Link]
}
}).catch(err => [Link]('Audit log error:', err));
return originalJson(data);
};
next();
};
};
// Usage
[Link]('/users/:id',
authenticate,
authorize('admin'),
audit('delete', 'user'),
async (req, res) => {
await [Link]([Link]);
[Link]({ status: 'success' });
}
);
7. Security Checklist
✓ Use HTTPS in production
✓ Hash passwords with bcrypt (12+ rounds)
✓ Implement rate limiting
✓ Validate and sanitize all input
✓ Use helmet for security headers
✓ Enable CORS properly
✓ Prevent NoSQL injection
✓ Prevent XSS attacks
✓ Implement CSRF protection
✓ Use secure session configuration
✓ Implement proper authentication
✓ Use role-based access control
✓ Keep dependencies updated
✓ Use environment variables for secrets
✓ Implement audit logging
✓ Regular security audits
✓ Error handling without info leakage
✓ Implement account lockout
✓ Use secure password reset flow
✓ Monitor for suspicious activity
8. Summary
In this part, we covered comprehensive authentication and security for [Link] applications:
• Password hashing and validation with bcrypt
• JWT authentication with access and refresh tokens
• Session-based authentication
• OAuth 2.0 integration (Google, GitHub)
• Role-based access control (RBAC)
• Essential security middleware (helmet, CORS, rate limiting)
• HTTPS and secure cookies
• CSRF and XSS protection
• Input validation and sanitization
• Two-factor authentication (2FA)
• API key authentication
• Audit logging
Security is not a one-time implementation but an ongoing process. Always stay updated with the latest security
practices and vulnerabilities.
9. What's Next in Part 8?
In Part 8, we'll explore Real-Time Communication, covering:
• WebSocket fundamentals
• [Link] for real-time bidirectional communication
• Building chat applications
• Real-time notifications
• Broadcasting and rooms
• Authentication with [Link]
• Scaling WebSocket applications
• Server-Sent Events (SSE)
This concludes Part 7 of the [Link] Complete Guide. Practice implementing these security measures to build
robust, secure applications that protect your users' data.