I am struggling to implement JWT refresh tokens with the Double Submit Cookies method.

My current set up for a browser based webapp without refresh tokens looks like this:

  • Upon successful login, API server returns JWT with expiry in a httponly cookie
  • Client server intercepts this and creates httponly cookie copying the jwt values from the header (need to do this as using node-fetch)
  • On each page request, client server reads httponly cookie, passing jwt value to page as a csrf variable. Meta tag is populated with this (for ajax to access), and hidden form values also pick up this so that they can also pass up csrf token in submit post requests.
  • Ajax request setup accesses the meta tag and creates a custom Authorization header with Bearer Token set to the csrf value. Upon ajax execution, api server now receives jwt in httponly cookie, and also the bearer token csrf value, and compares for equality.
  • Normal form request passes up form values to client server, where the csrf hidden form value is added to a custom authorization header as a bearer token, and this is passed up to api server, along with http only cookie. Once again, values are compared before access is granted.

So, I think current set up is working well, but I now want to add refresh tokens, to prevent user getting logged out during session. However, I can't see how to do this whilst following the Double Submit Cookie approach.

I think a refresh token API request would work similarly to above in terms of CSRF. The access token would now be very short lived, so I assume we could drop the csrf requirement for that, and just have csrf token for the longer lived refresh token. That means that the csrf check would only happen on the API refresh token requests (let me know, though, if you think this is problematic. Maybe I need two CSRF token values per page)

With this in mind, I see the following problem for ajax requests.

  • Upon ajax resource request failure due to access token expiry, fire an ajax refresh token request up to api server. Include refresh csrf token value in auth header so it can be compared against refresh token stored in httponly cookie (all very similar to current set up)
  • Following successful refresh request, receive both the new access token , and a new request token in httponly cookies.
  • Ajax Request is now performed with new access token (no csrf check?), and everything goes fine.
  • However, user stays on the same page, and then finally sends another resource request, but once again, the token has expired...
  • This time, the refresh token request will fail as it will attempt to use the old csrf token metadata value to populate the authorization header, and the comparison on the API server will fail.

So the problem is with Ajax requests: there is no opportunity to update the on-page csrf token after a successful refresh token request.

Are JWT refresh tokens broken because of this, or am I missing something in my set up?

  • couldn't you just update the DOM on Ajax callback? – pcalkins Feb 15 at 22:51
  • You mean, just include the new csrf token in the response body from the api? – Milambardo Feb 15 at 23:06
  • yes, but from the client server? (sry I've never used oauth so maybe I'm misunderstanding the flow... I assumed the client server sent requests to the auth api... not ajax... so client server gets the csrf token and passes it back to Ajax call after sending cookie headers.) – pcalkins Feb 15 at 23:42
  • 1
    Seems to me your original request (that fails) needs to reset the cookies, then modify the DOM (meta and/or hidden fields), then re-send the request. I'm assuming these requests are all done via javascript? – pcalkins Feb 16 at 0:05
  • 1
    They're done by both Ajax and Client Server, but in this particular scenario it is the Ajax I am concerned with. But I think you are right. The refresh request should update the DOM with the CSRF token passed in the response body. Like I say, I wasn't sure this was secure, but having done a bit of reading around the issue I'm more confident now. – Milambardo Feb 16 at 12:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.