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.
{"value":{"_key":"5c83cd99dc30","_type":"code","code":"import express from 'express';\nimport cors from 'cors';\n\nconst app = express();\n\nconst whitelist = ['https://myfrontend.com', 'https://admin.myfrontend.com'];\nconst corsOptions = {\n origin: (origin, callback) => {\n if (!origin || whitelist.indexOf(origin) !== -1) {\n callback(null, true);\n } else {\n callback(new Error('Blocked by CORS policy'));\n }\n },\n credentials: true, // Allow cookies\n};\n\napp.use(cors(corsOptions));","filename":"","language":"typescript"},"isInline":false,"index":3}
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.
{"value":{"_key":"f52195501ba3","_type":"code","code":"res.cookie('token', token, {\n httpOnly: true, // Prevents JS access\n secure: process.env.NODE_ENV === 'production', // Https only\n sameSite: 'strict', // Mitigates CSRF attacks\n maxAge: 3600000, // 1 hour\n});","filename":"","language":"javascript"},"isInline":false,"index":6}
3. Security Headers with Helmet
Helmet sets various HTTP headers to secure Express apps by default, protecting against clickjacking, script injections, and mime sniffing.
{"value":{"_key":"282ee68f1d14","_type":"code","code":"import helmet from 'helmet';\n\n// Apply helmet security headers\napp.use(helmet());","filename":"","language":"typescript"},"isInline":false,"index":9}
Following these security rules should be standard when initializing any production-ready Node.js API.