Suleman Ahmed - BlogBuilding Secure Node.js APIs: Best Practices for Authentication and CORS

Building a web API is easy, but making it secure requires deliberate practices. Node.js backends are susceptible to CSRF, XSS, and unauthorized requests if not configured properly.

1. Secure CORS Configurations

Cross-Origin Resource Sharing (CORS) limits who can fetch resources from your API. Avoid setting `Access-Control-Allow-Origin: *` in production, especially for APIs requiring authentication.

typescript snippettypescript
import express from 'express';
import cors from 'cors';

const app = express();

const whitelist = ['https://myfrontend.com', 'https://admin.myfrontend.com'];
const corsOptions = {
  origin: (origin, callback) => {
    if (!origin || whitelist.indexOf(origin) !== -1) {
      callback(null, true);
    } else {
      callback(new Error('Blocked by CORS policy'));
    }
  },
  credentials: true, // Allow cookies
};

app.use(cors(corsOptions));

2. JWTs in HttpOnly Cookies

Do not store JWT tokens in localStorage. If your app is vulnerable to an XSS (Cross-Site Scripting) attack, scripts can read localStorage. Instead, use secure, HttpOnly, SameSite cookies.

javascript snippetjavascript
res.cookie('token', token, {
  httpOnly: true, // Prevents JS access
  secure: process.env.NODE_ENV === 'production', // Https only
  sameSite: 'strict', // Mitigates CSRF attacks
  maxAge: 3600000, // 1 hour
});

3. Security Headers with Helmet

Helmet sets various HTTP headers to secure Express apps by default, protecting against clickjacking, script injections, and mime sniffing.

typescript snippettypescript
import helmet from 'helmet';

// Apply helmet security headers
app.use(helmet());

Following these security rules should be standard when initializing any production-ready Node.js API.

© 2026 Suleman Ahmed. All rights reserved.

Built with Next.js, Tailwind CSS & Sanity.