I'm creating a React Js website with a Node.js backend. I've been attempting to figure out a user authentication implementation to prevent CSRF attacks however I'm really confused about where to store Anti-CSRF tokens.
My thought process of a secure implementation is as follows...
- User submits request to login with credentials.
- Credentials are authenticated.
- Server creates session.
- Server creates JWT to use as Anti-CSRF token.
- Server stores JWT (Anti-CSRF token) in session storage.
- Server sends response to client.
- Response has header to store session ID in HttpOnly cookie on client-side.
- Response payload includes JWT (Anti-CSRF token).
- Client receives response.
- HttpOnly cookie holding session ID is stored on client-side.
- Client stores JWT (Anti-CSRF token) in localStorage.
I figure when a user needs to request information, the client can send the JWT (Anti-CSRF token) via a header or payload, and the session ID will be sent automatically due to it being a cookie. Then, the server can check if the JWT (Anti-CSRF token) exists in the session storage.
I know that the JWT (Anti-CSRF token) will need to be refreshed at some point.
My confusion is due to storing the JWT (Anti-CSRF token) on the client side. I keep reading that it should only be stored on the server. But if it's only stored on the server it doesn't seem to be doing anything at all.
I thought of using both cookies and localStorage because it seems that if a request to the server needs both a HttpOnly cookie and something from localStorage to send back an "authorized" response, an attacker would need to both successfully ride a session and successfully implement an XSS attack to get the Anti-CSRF token.
I just started learning about CSRF and XSS recently so I could be completely wrong and there could be a huge flaw in my implementation that I'm missing. But my main question is... don't Anti-CSRF tokens need to be stored on the client AND the server?