36

I do understand that a header is the "cleaner" solution to transport an auth-token from a trusted system to another in a REST call. But when you are in client-side JavaScript code, the world looks different to me.

Cookies can be marked as "http-only" and thus can't be easily stolen by JavaScript. A header even has to be set by JavaScript, thus the auth token has to be accessible from within JavaScript. But yet, people use auth-headers to submit their auth-tokens from an untrusted client JavaScript to the server.

What has changed from the good old "use cookies with http-only and secure flag" to "let the JavaScript handle the auth token"? Or should the right way be that "on the client side, use cookies and as soon as you enter the trusted world, switch to auth-header"?

PS: I know that there are many answers to similar questions, but I think my questions is from a different point of view "what has changed, is different".

Anders
  • 64,406
  • 24
  • 178
  • 215
rdmueller
  • 2,413
  • 3
  • 18
  • 17

3 Answers3

24

Cookie Based Authentication

Pros

  1. HttpOnly Flag: Session cookies can be created with the HttpOnly flag which secures the cookies from malicious JavaScript (XSS-Cross-Site Scripting).

  2. Secure flag: Session cookies can be created with Secure flag that prevents the cookies transmission over an unencrypted channel.

Cons

  1. CSRF: Cookies are vulnerable/susceptible to CSRF attacks since the third party cookies are sent by default to the third-party domain that causes the exploitation of CSRF vulnerability.

  2. Performance and Scalability: Cookie based authentication is a stateful authentication such that server has to store the cookies in a file/DB in order to maintain the state of all the users. As the user base increases the backend server has to maintain a separate system so as to store session cookies.

Token Based Authentication:

Pros

  1. Performance and Scalability: Tokens contains the metadata and its signed value(for tamper protection). They are self-contained and hence there is no need of maintaining state at the server. This improves the performance and thus scalability when the expansion is required.

  2. CSRF: Unlike cookie-based authentication, token-based authentication is not susceptible to Cross-Site Request Forgery since the tokens are not sent to third party web applications by default.

Cons

  1. XSS: Since the session tokens are stored in the local data storage of the browser and it is accessible to the JS of the same domain. Hence there is no option to secure session identifier from XSS attacks unlike HTTPOnly security flag which is available in the cookie-based authentication.

Conclusion

Both of the mechanisms have their own pros and cons as mentioned.In the present era of Application Development Frameworks, cons such as XSS and CSRF are taken care by the underlying framework itself and hence I feel it is without a doubt a clear trade-off on which developers and the stakeholders takes the decision.

Shiv Sahni
  • 921
  • 8
  • 16
  • 9
    I just learned that a combination might yield better results: a JWT stored as cookie together with a CSRF id send as header and stored as check in the JWT... – rdmueller Feb 23 '18 at 16:58
  • 1
    Yes you have learnt correct. The combination is indeed better. I hope you got the answer. – Shiv Sahni Feb 23 '18 at 17:07
  • 2
    let's drop this video (which helped me) here and close the question: https://www.youtube.com/watch?v=67mezK3NzpU – rdmueller Feb 23 '18 at 17:39
  • 1
    The XSS one is not quite right. With XSS the cookies authentication is only slightly better, because attacker can still CSRF. XSS allows attacker to bypass CSRF token. – Franklin Yu Aug 02 '18 at 04:00
  • 7
    `cons` for cookies are wrong. 1. Even when you use token, the browser continue `to send third party cookies to third party domain`. Thus this belongs to your app in a whole and do not belongs to your cookies 2. You can store TOKEN as session identificator. Thus no need `server has to store the cookies in a file/DB`. See [here](https://github.com/IdentityServer/IdentityServer3/issues/2039#issuecomment-288135399) – Eugen Konkov Oct 29 '18 at 12:32
  • interesting [article1](http://www.redotheweb.com/2015/11/09/api-security.html) and [article2](https://stormpath.com/blog/where-to-store-your-jwts-cookies-vs-html5-web-storage) – Eugen Konkov Oct 29 '18 at 13:57
  • 7
    Surprised to see this has so many upvotes. Both cons for cookies are wrong as @EugenKonkov mentioned. This answer is conflating session based auth with cookies. Cookies are a transport mechanism, they are neither stateful or stateless, it's what you put inside them that is. Also "cookies are sent by default to the third-party domain" is wrong, cookies are only sent to the site they were issued by. Another site can make a request to the target and the cookies belonging to the target may be sent along with it - which is where the CSRF threat can arise. – Melbourne2991 May 20 '19 at 08:02
  • @Melbourne2991, I believe you need to re-read the answer as it solely talks about the comparison of session management using cookies and stateless tokens such as JWT. Also, I think you need to patiently read the complete line for the better understanding of the context i.e. "third party cookies are sent by default to the third-party domain" which means that the third party cookies are sent by default to their RESPECTIVE domains. I hope this helps now! – Shiv Sahni May 20 '19 at 08:10
  • @ShivSahni in that case the answer needs editing, because it says "third party domains" which has a different meaning altogether. I can store a stateless JWT in a cookie instead of local storage - which is actually safer - so how can you say that cookies are stateful? Session based auth is stateful - where you are maintaining a session id in the backend, but this is a separate issue. – Melbourne2991 May 20 '19 at 08:13
  • 1
    @rdmueller "I just learned that a combination might yield better results: a JWT stored as cookie together with a CSRF id send as header and stored as check in the JWT..." this is correct! – Melbourne2991 May 20 '19 at 08:31
  • 4
    The answer is conflating two things: Storage method (Cookies vs LocalStorage) and Authentication Method: (Session vs JWT). You can mix and match all of them: Sessions in Cookies; Sessions in LocalStorage; JWT in Cookies; JWT in LocalStorage. Storage choice is mostly front-end. If you do use Cookies, then make sure it's HttpOnly and make sure you use CORS. If you use LocalStorage, make sure you're safe from XSS. AUTH choice is mostly back-end choice. I suggest HTTPOnly JWT Cookies with CORS on the server which allows fully unaware & transparent requests from JS. (Use 401/403/200 codes.) – ShortFuse Sep 02 '19 at 17:15
  • The CSRF problem of cookies goes away with the `sameSite` flag. – Pier Oct 24 '20 at 17:13
  • 1
    I think this answer is mixing cookies with session and access token with local storage. Saying "Cookie based authentication is a stateful authentication" is wrong because you can have a JWT stored as a cookie. Actually, we can have 4 combinations regardless of vulnerabilities. And indeed, many suggest that we should store the access token as an HttpOnly, SameSite, Secure cookie instead of local storage to prevent from CSRF and XSS attacks (can also combine with the use of a CSRF token). Would have downvoted this answer but I don't have sufficient reputation. – blackr1234 May 13 '21 at 23:26
  • I think Cookie != Stateful. You can use cookie to store access token – Kevin May 29 '21 at 03:34
16

The accepted answer is conflating session based authentication - where a session is maintained in backend database and is stateful with cookies, which are a transport mechanism and so the pros and cons are flawed.

As to whether an auth token should be stored in a cookie or a header, that depends on the client. If the client is another REST api, then passing it via the header makes sense.

If the client is a browser you could store the token in local/session storage and then send the token via the header (as the accepted answer says), but as you mentioned - this has vulnerabilities and is not recommended (see more on this here: https://auth0.com/docs/security/store-tokens).

If the client is an SPA you could just store the tokens in memory - which is probably the safest option, but then you will need retrieve new tokens between pages.

If you need persistence between pages, "the old fashioned way" may still be the best option - providing your cookies are http-only, secure, and you have implemented csrf protection (though soon this may not be necessary because of the same-site property). Providing you do implement csrf protection you will get all of the benefits of "cookie-less token based auth" and additional protection against XSS.

Melbourne2991
  • 261
  • 2
  • 3
  • 1
    I agree that the accepted answer is mixing cookies with session and access token with local storage. Actually, we can have 4 combinations regardless of vulnerabilities. – blackr1234 May 13 '21 at 23:18
  • When you say "If the client is an SPA you could just store the tokens in memory", is this something that someone will actually do in real world? IMHO, the major reason why cookie or local storage is used is to maintain state even if the user closes the webpage. Will certain implementations, such as using React Redux for state management, still cause the data to be vulnerable to XSS attack? – blackr1234 May 13 '21 at 23:22
5

The accepted answer is totally wrong!

Please don't mix Cookie, Token, Stateful, Stateless. So many people consider Cookie == Stateful. No it's totally wrong!

Stateful == Session-based -> You store data on server and client just hold session_id, opaque_token.

Stateless -> You don't store anything on server, all data is embedded into token, client hold token and send to server to authentication/authorization. Token can be in JWT, PASETO or any format.

Cookie is just transportation. You can use Cookie or Authorization Header to send token/session_id/opaque_token.

Kevin
  • 151
  • 1
  • 2