— You basically have to get rid of all XSS vulnerabilities to make it hardened, put jwt in HTTPOnly, SSL-only cookie that no client script can access, then refresh token in localstorage
It's totally at odds with all anti CSRF knowledge out there, and hard to implement securely unless you have revocation
— I similarly used to deploy jwt in SPA/webapi apps and found the same, wrote my own jwt library, and spent a year researching how to secure it... without a blacklist table there is no way to secure it in a way that would let me sleep at night personally
— Otherwise, even if your app is aware of CSRF, it can't stop it
— So the right way is?
— 10 Best Practices for Writing Node.js REST APIs | RisingStack
— In order for an attacker to see session data, they would need to be able to send both the CSRF token and cookie, one of which they can't read, and the other they can't get if there are no XSS holes
— You can store a hashed CSRF token in localstorage and keep the unhashed one in the JWT.
— Set cookie, check cookie
— The cookie is sent automatically, so by itself is a huge CSRF risk. But, since it is HTTPOnly, scripts cant see it! The hashed localstorage CSRF token is only available to scripts on the domain, so as long as you prevent XSS, nothing would be able to compromise the tokens.
— It is vastly more complex and high risk compared to server sessions and traditional CSRF token embedding