In a Typescript-React SPA, I'm trying to access the document.cookie
in order to retrieve a token sent together with a JWT cookie, intended to protect my Flask API against CSRF attacks, as described here.
The basic idea is that my API will send 2 cookies: one containing the JWT and flagged with the Secure
& HttpOnly
attributes, and another one that should be readable by JS with a token that, when sent back in the request Headers
to the server should match a token encrypted in the JWT and thus verify if it's a CSRF attack or not.
To grab said token, I'm using the following function:
export default function getCSRFCookie() {
console.log(document.cookie);
const cookiesString = `; ${document.cookie} `;
const CSRFCookie = cookiesString.split(`; csrf_access_token=`);
return CSRFCookie.length === 2 ? CSRFCookie.pop()?.split(';').shift() : '';
}
However, document.cookie
always ends up being an empty string, even although the relevant cookie doesn't have the HttpOnly
flag, which is the one that prevents JS from reading it in document.cookie
:
csrf_access_token=<token_value>;
Expires=Wed, 21 Dec 2022 00:33:53 GMT;
Max-Age=7200; Secure; Path=/;
SameSite=None
The following are the relevant Flask & Flask JWT Extended configurations that set the cookies up, but personally I don't think this is a server issue, because I saw, the cookies have the correct attributes matching the settings below:
# Flask JWT Extended specific configurations:
JWT_COOKIE_CSRF_PROTECT = True
JWT_COOKIE_SECURE = True
JWT_COOKIE_SAMESITE = "None"
# Flask config values, which are explicitly set to override default values.
# See https://flask.palletsprojects.com/en/2.2.x/security/#security-cookie
SESSION_COOKIE_HTTPONLY = False
SESSION_COOKIE_SAMESITE = "None"
The Flask application is already deployed in Linode, has got its own domain as well as an SSL certificate. I believe this is a front end problem.
I've tried to:
- Access from
http://127.0.0.1:3000
instead oflocalhost
, as a comment in this answer suggests. - Access from both HTTPS (through
HTTPS=true npm run start
) and regular HTTP. - Check any default setting that might set the wrong attribute implicitly (such as Flask's
SESSION_COOKIE_HTTPONLY
, but as I wrote above, all those attributes appear to be correct and besides, the cookie I get doesn't have theHttpOnly
attribute. - The
SameSite
attribute is already set toNone
, as several comments and answers suggest in this question - Deleting all the cookies sent by my API before trying again after a change.
In order to continue working in other features, I've provisionally set the JWT_COOKIE_CSRF_PROTECT
property to False
, but that cannot remain that way since it's an obvious security risk.