Express.js Authentication

Implement secure authentication in Express.js using JWT, sessions, Passport.js, and OAuth. Learn best practices for protecting your API.

Overview

Authentication is a critical aspect of web application security. Express.js provides flexibility in implementing various authentication strategies.

Authentication Methods

Common authentication methods include: - **Session-based**: Traditional approach using cookies and server-side sessions - **Token-based (JWT)**: Stateless authentication using JSON Web Tokens - **OAuth/OAuth2**: Third-party authentication (Google, GitHub, etc.)

JWT Authentication

JSON Web Tokens are popular for API authentication. They're stateless, scalable, and work well with modern frontend frameworks.

Passport.js

Passport is authentication middleware for Node.js. It's extremely flexible and modular, supporting many authentication strategies.

Security Best Practices

Always hash passwords, use HTTPS, implement rate limiting, and follow security best practices to protect your users.

Code Examples

JWT Authentication Setup

auth/jwt.js
const jwt = require('jsonwebtoken');
const bcrypt = require('bcryptjs');

// Generate JWT token
const generateToken = (userId) => {
  return jwt.sign(
    { id: userId },
    process.env.JWT_SECRET,
    { expiresIn: '7d' }
  );
};

// Login route
app.post('/login', async (req, res) => {
  const { email, password } = req.body;

  const user = await User.findOne({ email });
  if (!user || !await bcrypt.compare(password, user.password)) {
    return res.status(401).json({ error: 'Invalid credentials' });
  }

  const token = generateToken(user._id);
  res.json({ token, user: { id: user._id, email: user.email } });
});

Protect Routes Middleware

middleware/protect.js
const protect = async (req, res, next) => {
  try {
    // Get token from header
    const authHeader = req.headers.authorization;
    if (!authHeader?.startsWith('Bearer ')) {
      return res.status(401).json({ error: 'Not authorized' });
    }

    const token = authHeader.split(' ')[1];

    // Verify token
    const decoded = jwt.verify(token, process.env.JWT_SECRET);

    // Attach user to request
    req.user = await User.findById(decoded.id).select('-password');

    if (!req.user) {
      return res.status(401).json({ error: 'User not found' });
    }

    next();
  } catch (error) {
    res.status(401).json({ error: 'Not authorized' });
  }
};

// Protected route
app.get('/profile', protect, (req, res) => {
  res.json(req.user);
});

Password Hashing

auth/password.js
const bcrypt = require('bcryptjs');

// Hash password before saving
const hashPassword = async (password) => {
  const salt = await bcrypt.genSalt(12);
  return bcrypt.hash(password, salt);
};

// Register route
app.post('/register', async (req, res) => {
  const { email, password, name } = req.body;

  // Check if user exists
  const existingUser = await User.findOne({ email });
  if (existingUser) {
    return res.status(400).json({ error: 'Email already registered' });
  }

  // Hash password
  const hashedPassword = await hashPassword(password);

  // Create user
  const user = await User.create({
    email,
    password: hashedPassword,
    name
  });

  const token = generateToken(user._id);
  res.status(201).json({ token, user: { id: user._id, email } });
});

Frequently Asked Questions

Should I use sessions or JWT for authentication?
It depends on your use case. JWTs are great for APIs and SPAs as they're stateless and scalable. Sessions are simpler for traditional web apps and offer easier revocation. Consider your architecture and requirements.
How do I refresh JWT tokens?
Implement a refresh token strategy. Issue both an access token (short-lived) and a refresh token (long-lived). When the access token expires, use the refresh token to get a new access token.
How do I protect against brute force attacks?
Implement rate limiting using packages like express-rate-limit, add account lockout after failed attempts, use CAPTCHA for login forms, and consider adding 2FA.

Need expert help with Express.js?

Our team at Slashdev.io builds production-ready Express.js applications.