Full-Stack Architecture Patterns

Master architecture patterns for building scalable full-stack applications.

intermediate Backend Development 6 hours

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:

  1. User clicks "Login with Google"
  2. Redirected to Google login
  3. User authenticates with Google
  4. Google redirects back with authorization code
  5. Application exchanges code for access token
  6. 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