Security must be built in from the start, not added later.

Essential Packages

  npm install helmet cors express-rate-limit bcrypt jsonwebtoken
  
  import helmet from 'helmet';
import cors from 'cors';
import rateLimit from 'express-rate-limit';

app.use(helmet());
app.use(cors({ origin: process.env.ALLOWED_ORIGINS?.split(',') }));

const limiter = rateLimit({
    windowMs: 15 * 60 * 1000, // 15 minutes
    max: 100
});
app.use('/api/', limiter);
  

Password Hashing

Never store plain-text passwords:

  import bcrypt from 'bcrypt';

// Register
const salt = await bcrypt.genSalt(12);
const hashedPassword = await bcrypt.hash(password, salt);

// Login
const isValid = await bcrypt.compare(inputPassword, user.password);
  

JWT Authentication

  import jwt from 'jsonwebtoken';

function generateToken(userId) {
    return jwt.sign({ userId }, process.env.JWT_SECRET, { expiresIn: '7d' });
}

function verifyToken(req, res, next) {
    const token = req.headers.authorization?.split(' ')[1];
    if (!token) return res.status(401).json({ error: 'No token' });

    try {
        req.user = jwt.verify(token, process.env.JWT_SECRET);
        next();
    } catch {
        res.status(401).json({ error: 'Invalid token' });
    }
}
  

Input Validation

Always validate and sanitize user input:

  import { body, validationResult } from 'express-validator';

app.post('/register',
    body('email').isEmail().normalizeEmail(),
    body('password').isLength({ min: 8 }),
    (req, res) => {
        const errors = validationResult(req);
        if (!errors.isEmpty()) return res.status(400).json({ errors: errors.array() });
        // Proceed...
    }
);
  

SQL/NoSQL Injection Prevention

Use parameterized queries — ORMs like Prisma and Mongoose handle this:

  // BAD — never do this
db.query(`SELECT * FROM users WHERE email = '${email}'`);

// GOOD — use ORM
await User.findOne({ email });
  

Security Checklist

  • Use HTTPS in production
  • Store secrets in environment variables
  • Hash passwords with bcrypt (cost factor ≥ 12)
  • Validate all input
  • Rate limit auth endpoints
  • Set secure cookie flags (httpOnly, secure, sameSite)
  • Keep dependencies updated (npm audit)
  • Don’t expose stack traces in production
  • Implement proper CORS policy
  • Use helmet for security headers

See also Security in JavaScript for client-side security topics.