I'm trying to implement the Double Submit Cookie pattern with extra protection using encrypted or signed CSRF tokens. I'm working with a Single Page Application and a stateless API. The purpose of this is to reduce risk of an attacker setting the tokens. This should be implemented with HSTS too.

I understand the non-encrypted workflow of Double Submit Cookie (No HMAC, No encryption):

  1. The user goes into the page and gets a token (preferably before login to avoid login CSRF). The token is passed from the server to the client as a Http-Only=false cookie. Let's call this "Cookie A".

  2. Whenever the client is going to send a request, it reads the value of "Cookie A" with JavaScript and attaches the token as a hidden form field or as a HTTP header. The client also sends "Cookie A" to the API with the request.

  3. The API validates that the value of "Cookie A" matches the value from the form field or the HTTP header.

Please correct me if these steps are wrong.

In the encrypted or HMAC version of the process, I don't understand how the server sends both the encrypted/HMAC AND the plain-text CSRF token to the client.

  • Is the server supposed to send 2 cookies? 1 encrypted/HMAC and 1 plain-text?
  • Is the encrypted/HMAC cookie Http-Only=true?
  • Does HSTS render encrypted/HMAC cookies useless?

There's no further information in OWASP about how to implement this. Further guidance is much appreciated.

  • Why would you set this as HTTP-ONLY=FALSE?? And why would you let client-side JS create the token?? As I understand it, the point of the encryption for the hidden field value is so only the server can create and decrypt that hidden field value which can then be evaluated against the cookie. (and you can create a new key/value for each form if you like... the cookie can remain the same and be refreshed only when the session is)
    – pcalkins
    Feb 10 at 19:21
  • @pcalkins to summarize the question: How would you send the encrypted token and unencrypted token from the server to the client? Would you use 2 cookies? If so, which attributes would these cookies have for domain, path, sameSite, httpOnly... OWASP does not clarify these questions.
    – AFP_555
    Feb 11 at 6:29
  • double-submit uses 1 cookie, and 1 parameter (usually a hidden field in the form). You'd set the cookie when a session is begun. Same domain or it won't be sent automatically with each request. samesite, httponly, and secure options are very good options to set for security. The hidden field inside the form ties the session to the form. It's harder to impersonate... since this value changes.... either with each new session or with each request for the form. There are also alternative techniques which use custom headers.
    – pcalkins
    Feb 11 at 16:51
  • I think the confusion comes with the session cookie and the anti-csrf cookie. Those would be the 2. The server can send a request for the browser to store a cookie.... then it will send another request for redirect. Those two things can also be sent via javascript... (the server would send back some data... the JS writes the cookie, then updates the DOM accordingly) either way you want those requests to be secure and same domain.
    – pcalkins
    Feb 11 at 16:57
  • @pcalkins OK, so 1 cookie is the session ID and the other cookie is the CSRF token. I'm working with a Single Page App and JWT tokens for Auth. Also, the API is stateless. I'm not sure if I should have sessions.
    – AFP_555
    Feb 11 at 19:44

1 Answer 1


I have implemented this using HMAC and below are the steps:

  1. Generate HMAC using session_id, timestamp with 19 digits, logged in user_id
  2. Now prepend the same timestamp to the token above, timestamp + hmac_hash
  3. Set that token from step-2 in cookies as CSRF token
  4. FE will read the csrf token from cookie and pass it in header
  5. BE will read the csrf token token from header
  6. Extract the timestamp -- first 19 chars from csrf_token
  7. Extract the HMAC hash which is a string after first 19 chars.
  8. Re-generate hmac hash using session_id, user_id, timestamp
  9. Securly compare the computed hash against the hash present in point 7. There can be a function in your technology to compare them securly.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .