In my React + Django project, I’m currently sending the refresh token as an HttpOnly cookie. The problem with HttpOnly cookies is that they are automatically sent by the browser, which makes them vulnerable to CSRF attacks. To address this, I decided to add a CSRF token for the refresh request. However, the issue I’m facing is that I’m unable to read the CSRF token using JavaScript. I think this is because my frontend and backend are on different domains. When I searched online, I found that cross-site cookies can’t be read by JavaScript. If that’s true, what are the possible ways to protect the refresh token request?
2 Answers
On the domain that issues the cookie, set a CORS response header like this, with your header name, so that JS can read the csrf header:
Access-Control-Expose-Headers: csrf
ALTERNATIVE OPTION
CSRF tokens are a little awkward though, e.g. you might need to store them in local storage for multi-tab browsing to work reliably, which is not very satisfactory.
Instead, you can use SameSite and CORS to implement CSRF protection, without the need for the CSRF header:
- Use SameSite=strict to prevent other sites from sending the refresh cookie.
- Use CORS to restrict access to other origins in the same site as the React app.
- Server endpoints that use the refresh token can require a custom header like
version=1to prevent simple requests from other origins bypassing CORS restrictions.
You can read more about this pattern in the OAuth for Browser Based Apps document.
Comments
You don’t need to read the refresh cookie with JS (and shouldn’t). Instead, pair it with a separate CSRF token mechanism (double-submit cookie pattern) or rely on SameSite cookies. Django already supports this workflow out of the box.