Here is an explainer of how cookies work. TLDR:
- Browser sends HTTP request to server.
- Server sends HTTP response with
Set-Cookie: cookie=monster
header, which sets the cookie in the browser. - Every subsequent request the browser sends to the server will have the
Cookie: cookie=monster
header.
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)