Chapter 5: Authentication Patterns
Chapter 5 of 15
Chapter 5: Authentication Patterns
5.1 Authentication Methods
Authentication verifies user identity. Different methods suit different use cases and security requirements.
Session-Based Authentication:
- Server creates session when user logs in
- Session ID stored in cookie
- Server maintains session state
- Good for traditional web applications
- Requires server-side session storage
// Session creation (Express.js)
app.post('/login', (req, res) => {
const user = authenticateUser(req.body);
req.session.userId = user.id;
res.redirect('/dashboard');
});
// Session validation middleware
const requireAuth = (req, res, next) => {
if (req.session.userId) {
next();
} else {
res.redirect('/login');
}
};
Token-Based Authentication (JWT):
- Stateless authentication
- Token contains user information
- Client stores token (localStorage, cookie)
- Good for APIs and SPAs
- Scalable across multiple servers
// JWT creation
const jwt = require('jsonwebtoken');
const token = jwt.sign(
{ userId: user.id, email: user.email },
process.env.JWT_SECRET,
{ expiresIn: '24h' }
);
// JWT verification
const decoded = jwt.verify(token, process.env.JWT_SECRET);
OAuth 2.0:
- Third-party authentication
- Users authenticate with providers (Google, Facebook, GitHub)
- Application receives access token
- No password storage required
- Common for social login
OAuth Flow:
- User clicks "Login with Google"
- Redirected to Google login
- User authenticates with Google
- Google redirects back with authorization code
- Application exchanges code for access token
- Application uses token to access user data
5.2 Authorization
Authorization determines what authenticated users can access. Implement role-based access control (RBAC) and permissions.
Role-Based Access Control (RBAC):
- Users assigned roles (admin, user, moderator)
- Roles have specific permissions
- Check role before allowing actions
- Flexible and scalable
// Role checking middleware
const requireRole = (role) => {
return (req, res, next) => {
if (req.user.role === role || req.user.role === 'admin') {
next();
} else {
res.status(403).json({ error: 'Insufficient permissions' });
}
};
};
// Usage
router.delete('/users/:id', requireAuth, requireRole('admin'), deleteUser);
Permission-Based Authorization:
- Fine-grained control
- Users have specific permissions
- More flexible than roles
- Can combine with roles
// Permission check
const hasPermission = (user, permission) => {
return user.permissions.includes(permission) ||
user.role === 'admin';
};
if (hasPermission(req.user, 'delete_users')) {
// Allow deletion
}
5.3 Password Security
Proper password handling is critical for security.
Password Hashing:
- Never store plain text passwords
- Use strong hashing algorithms (bcrypt, argon2)
- Include salt for uniqueness
- Use appropriate cost factor
// Password hashing (bcrypt)
const bcrypt = require('bcrypt');
const saltRounds = 10;
// Hash password
const hashedPassword = await bcrypt.hash(password, saltRounds);
// Verify password
const isValid = await bcrypt.compare(password, hashedPassword);
Password Requirements:
- Minimum length (8+ characters)
- Mix of uppercase, lowercase, numbers, symbols
- Check against common password lists
- Enforce password changes periodically
5.4 Security Best Practices
Follow security best practices to protect authentication systems.
- Use HTTPS for all authentication
- Implement rate limiting on login attempts
- Set secure cookie flags (HttpOnly, Secure, SameSite)
- Implement account lockout after failed attempts
- Use CSRF protection
- Log authentication events
- Implement two-factor authentication (2FA) for sensitive accounts