← Back to all snippets
JAVASCRIPT

Implement CSRF Protection in Node.js Express Apps with Tokens

Protect your Node.js Express application from CSRF attacks by generating and validating anti-CSRF tokens for form submissions.

const express = require('express');
const session = require('express-session');
const bodyParser = require('body-parser');
const crypto = require('crypto'); // For generating random tokens

const app = express();
const port = 3000;

// Use session middleware (requires a session store for production)
app.use(session({
    secret: 'your_strong_secret_key', // Replace with a strong, unique secret
    resave: false,
    saveUninitialized: true,
    cookie: { secure: false } // Set to true if using HTTPS
}));

app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());

// CSRF Token Generation Middleware
app.use((req, res, next) => {
    if (req.method === 'GET' || req.method === 'HEAD' || req.method === 'OPTIONS') {
        // No CSRF token needed for safe methods
        return next();
    }

    // Generate a new CSRF token if one doesn't exist in the session
    if (!req.session.csrfToken) {
        req.session.csrfToken = crypto.randomBytes(32).toString('hex');
    }
    res.locals.csrfToken = req.session.csrfToken; // Make token available to templates
    next();
});

// CSRF Token Validation Middleware for POST requests
function csrfProtection(req, res, next) {
    if (req.method === 'GET' || req.method === 'HEAD' || req.method === 'OPTIONS') {
        return next(); // Skip for safe methods
    }

    const clientToken = req.body._csrf || req.headers['x-csrf-token'];
    const sessionToken = req.session.csrfToken;

    if (!clientToken || !sessionToken || clientToken !== sessionToken) {
        console.error('CSRF token mismatch or missing.');
        return res.status(403).send('CSRF token mismatch. Request blocked.');
    }

    // Token is valid, proceed
    next();
}

// --- Routes ---
app.get('/', (req, res) => {
    // For demonstration, render a simple form with the token
    res.send(`
        <h1>Welcome</h1>
        <p>Your CSRF token for this session: <strong>${req.session.csrfToken}</strong></p>
        <form action="/transfer" method="POST">
            <input type="hidden" name="_csrf" value="${req.session.csrfToken}">
            <label for="amount">Amount:</label>
            <input type="text" id="amount" name="amount" value="100">
            <br>
            <input type="submit" value="Transfer Money">
        </form>
        <p>Try inspecting the form to see the hidden token.</p>
        <p>To simulate an attack, remove the hidden input field and resubmit.</p>
    `);
});

// Apply CSRF protection to routes that modify state
app.post('/transfer', csrfProtection, (req, res) => {
    const { amount, _csrf } = req.body;
    // In a real app, perform the transfer operation here
    res.send(`Transfer of ${amount} successful! (CSRF token: ${_csrf})`);
});

app.listen(port, () => {
    console.log(`Server running at http://localhost:${port}`);
    console.log('Access http://localhost:3000 to test the CSRF protection.');
});
How it works: Cross-Site Request Forgery (CSRF) attacks trick users into executing unwanted actions on your web application. This Node.js Express snippet demonstrates CSRF protection using synchronizer tokens. A unique token is generated for each user session and embedded in forms (often as a hidden input) or sent via headers for API requests. On submission, the server verifies if the submitted token matches the one stored in the user's session. If they don't match, the request is rejected, preventing attackers from forging requests on behalf of authenticated users.

Need help integrating this into your project?

Our team of expert developers can help you build your custom application from scratch.

Hire DigitalCodeLabs