Getting invalid CSRF token error when sending requests from React frontend to Express backend

I’m having trouble with CSRF protection in my Express app. I’ve set up the middleware correctly and it works when I test it with Postman, but when I try to make requests from my React frontend, I keep getting an invalid CSRF token error.

Here’s my Express server setup:

const csrfMiddleware = require('csurf');
const cookies = require('cookie-parser');

const tokenProtection = csrfMiddleware({
    cookie: {
        httpOnly: true,
        maxAge: 3600
    }
});

app.use(cookies());
app.use(tokenProtection);

app.get('/api/get-csrf', (request, response) => {
    response.json({ token: request.csrfToken() });
});

And here’s my React frontend code:

useEffect(() => {
    const fetchCsrfToken = async () => {
        const response = await apiClient.get('/api/get-csrf');
        apiClient.defaults.headers.post['X-CSRF-Token'] = response.data.token;
    };
    fetchCsrfToken();
}, []);

const submitForm = (event) => {
    event.preventDefault();
    apiClient.post('/api/signin', {
        headers: {
            'Content-Type': 'application/json'
        },
        data: { username, password },
    }).then((response) => {
        if (response.data.authToken) {
            localStorage.setItem('authToken', response.data.authToken);
            window.location.href = '/dashboard';
        }
    }).catch((error) => {
        console.log(error);
    });
}

The server keeps returning: ForbiddenError: invalid csrf token. What could be causing this issue?

Had the same issue - it’s usually a cookie domain problem. Your Express server needs to explicitly set the cookie domain to match your React dev server. Add sameSite: 'lax' and make sure the domain in your cookie settings is correct. Also check if React’s running on a different port than Express - cross-origin requests can block CSRF cookies even with CORS set up right. Try secure: false in your cookie options for development since HTTPS requirements mess with local testing.

you’re setting the header in axios defaults but then overriding it in the post request with a new headers object. move the csrf header inside the post call headers instead of using defaults - that should fix it.

Interesting issue! Are you handling cookies properly between React and Express? I’m wondering if the CSRF cookie is actually getting sent with your POST request. What’s your apiClient config look like for credentials?