
Here is an explainer of how cookies work. TLDR:
- Browser sends HTTP request to server.
 - Server sends HTTP response with 
Set-Cookie: cookie=monsterheader, which sets the cookie in the browser. - Every subsequent request the browser sends to the server will have the 
Cookie: cookie=monsterheader. 
I store a CSRF token in a cookie, which is used by the server to validate client-side HTTP POST requests. The server responds with a 403 if the cookie is missing in the HTTP request.
On the client-side, I have been using the cross-fetch package via the ponyfill approach.
import fetch from 'cross-fetch';
fetch('/some-route', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json'
    },
    body: { /* some payload */ }
});
One day, I decided to switch to the polyfill approach in order to use the native window.fetch.
import 'cross-fetch';
fetch('/some-route', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json'
    },
    body: { /* some payload */ }
});
A bunch of users started getting 403s.

After scouring Stack Overflow and the interwebs (and many tears later), the answer was in the MDN docs all along:
The users getting 403s were using browsers older than the versions listed above. So this was the fix:
import 'cross-fetch';
fetch('/some-route', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json'
    },
    body: { /* some payload */ },
    credentials: 'same-origin' // the fix
});
You might ask: what about Internet Explorer, your favorite problem child? Well, since it supports nothing, the polyfill kicks in with a version of fetch that sets same-origin as the default credentials policy, so no 403s.
Today I learned.

    
Top comments (0)