0% found this document useful (0 votes)
7 views17 pages

NodeJS Part7 Authentication Security

This document provides a comprehensive guide on authentication and security practices for Node.js applications. It covers topics such as password security, JWT authentication, role-based access control, OAuth integration, and essential security measures to protect applications from vulnerabilities. Additionally, it includes code examples and best practices for implementing these security features effectively.

Uploaded by

alvinregi
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
7 views17 pages

NodeJS Part7 Authentication Security

This document provides a comprehensive guide on authentication and security practices for Node.js applications. It covers topics such as password security, JWT authentication, role-based access control, OAuth integration, and essential security measures to protect applications from vulnerabilities. Additionally, it includes code examples and best practices for implementing these security features effectively.

Uploaded by

alvinregi
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

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 || ![Link]('Bearer ')) {


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 (![Link]([Link])) {
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.

You might also like