top | item 16517412

Ask HN: Cookies vs. JWT vs. OAuth

260 points| amend | 8 years ago | reply

I’m using passport.js with a local strategy for authentication, and I’m using sessions/cookies for keeping state and keeping the user logged in.

I’m not very knowledgeable in security (that’s why I’m asking here), but will using JWT (with the token stored in the cookie) to keep the user logged in instead of sessions/cookies make my application more secure when the passport middleware executes req.isAuthenticated? I thiiink somewhere in that call it checks cookies or jwt, depending on implementation.

Also, I do not plan on opening the API to other sites, so OAuth is unnecessary. Is my understanding correct?

93 comments

order
[+] TheAceOfHearts|8 years ago|reply
No, using JWT will not make your application more secure. Continue using cookies. Don't buy into the JWT hype. You'll probably want to add a CSRF token.

You're correct in stating that implementing an OAuth provider is unnecessary.

I suggest reading the OWASP security guides. Start with Session Management Cheat Sheet [0], and after that Cross-Site Request Forgery (CSRF) [1].

Don't fear the cookies, all their gotchas are well documented and understood. There's lots of valid use-cases for stuff like JWT and OAuth, but I wouldn't bother with it at all until you're more comfortable with digging into the AuthN/AuthZ minefield. I'd consider understanding session management with cookies a precursor to trying to do anything fancier.

[0] https://www.owasp.org/index.php/Session_Management_Cheat_She...

[1] https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(...

[+] gizzlon|8 years ago|reply
> "No, using JWT will not make your application more secure. Continue using cookies"

Cookies vs JWT makes no sense. You can put the JWT in a cookie if you want to.. apples and oranges.

[+] dwaite|8 years ago|reply
Agreed, the essential piece is finding a reference to understand the security issues.

Technology choices don't replace the need to understand that (although some choices may affect the urgency through unsafe defaults).

[+] welder|8 years ago|reply

[deleted]

[+] modernpacifist|8 years ago|reply
To answer as best as possible given the vagueness:

Cookies: Highly compatible with most if not all browsers (and even headless tools). Lends themselves to having an expiry date and generally best when used with time sort of short-lived expiring session.

JWT: Everyone tends to use these in a stateless manner which means once issued, somewhat impossible to revoke without invalidating all JWTs or having a blacklist (and we're back at stateful). Plus some implementations had issues with downgrade attacks I think it was...

OAuth 1: Fine assuming you could keep clocks in sync and guarantee the secure storage of the keys/secrets. Good in that it didn't rely on HTTPS but if the secrets ever got compromised then the attacker would have free reign of that account until detected.

OAuth 2: Basically a complicated way to get short lived session tokens, potentially from a 3rd party API/auth source. Relies entirely on HTTPS to keep data secure in-transit and less of an issue if the session token gets compromised since its ideally short lived (because most want it to be stateless - those who keep a valid list of tokens sometimes skip the token expiry).

[+] dwaite|8 years ago|reply
Re: OAuth 2, once you carve out everything but the code flow and token refreshes it becomes harder to imagine simplifications that don't remove important functionality.

The flow becomes "redirect the user to have them authenticate, getting back a code. Make an API call to trade that code in for access. Once access expires, try to refresh it. If refreshing fails, send the user back to re-authenticate.".

The challenge people tend to hit is mistakenly trying to implement broad + reusable code at the start. OAuth 2 is described as a framework (e.g. optional parts and extensions leading to most likely non-interoperable implementations). Without a profile like OpenID Connect Basic Client, this includes a lot of extra work. Once you stop striving to implement generic interoperability in your client (or shoot for a limited profile like OpenID Connect Basic Client), the whole client implementation can fit in < 1 page of code.

[+] tetraodonpuffer|8 years ago|reply
> JWT: Everyone tends to use these in a stateless manner which means once issued, somewhat impossible to revoke

you can still do an oauth-like session + refresh token even with your own JWT implementation, just have a "refresh my session" endpoint that you go to with your refresh token (which is blacklistable), and have all the other calls be authenticated with the short-expiry stateless session token instead.

[+] kevlened|8 years ago|reply
Before going all the way on cookies, make sure to consider whether you're creating a mobile app, as mobile apps usually don't handle cookies for you automatically. In my experience, OAuth is a bit easier in mobile. If you support cookies for browsers and OAuth for mobile, your API will have to support both authentication methods.
[+] dwaite|8 years ago|reply
To be clear, OAuth 1 security over HTTP was pretty terrible all around. The cryptographically signed requests only supported a small subset of possibly HTTP requests (i.e. it didn't protect a JSON POST), and there was no protection whatsoever on server responses.

It doesn't do nearly as much good as one would hope knowing that a request came from a particular client if that request was possibly based on erroneous data, manipulated by a malicious third party.

[+] mezzode|8 years ago|reply
Having a blacklist is probably still preferable to storing every session though in that there should be less data stored, if only marginally
[+] amend|8 years ago|reply
I just updated my question, as it was vague. I’d appreciate your input!
[+] cygned|8 years ago|reply
Every time I looked at OAuth I found it overly complex for what I wanted to do. Thus, never actually implemented that, maybe I am missing something on that, though.

JWT is great until you get to the point where you want to have things like token revocation.

A simple session mechanism we use for our apps:

- Upon sign in, generate a session token, e.g. 32 characters. Session tokens are unique and fully random, not derived from any actual data

- In our scenario, a user can have multiple session at a time. We store two mappings in a Redis database; user-id=>user-object (for caching purposes, serialized JSON) and session-id=>user-id

- The second mapping has an expiration time which is the session length eventually, e.g. 30 minutes

- Upon every request, we take the session id from the request (header or cookie, cascadingly) and look for the session-id in Redis. If found, we prolong the time to live of that entry. From Redis, we got the user-id (because of the mapping) and thus we can retrieve the cached user object, too.

So we have a meaningless token (at least externally), our backend is still stateless (at least the application itself, Redis is stateful in nature) and we don't have to reinvent any wheels for automatically terminating sessions. In addition, it's easy to cancel session on demand and build a blacklist.

We wrote the handling ourselves (except for the crypto of course), because no express.js related library/middleware was flexible enough. And eventually we kind of trusted nobody.

[+] Ninn|8 years ago|reply
> JWT is great until you get to the point where you want to have things like token revocation.

What a flawed argument, there are techniques that allows for session revocation, even in an async stateless jwt context, i.e. By blacklisting, which will work great, and give you some nice properties, depending on your infrastructure and design.

Sadly, some appear to assume jwt is some special solution that does X right and y wrong.. but its really nothing other than a structured format in the end. But surely a lot of people do a lot of wrong stuff when deploying their stuff on top of jwt.

[+] venantius|8 years ago|reply
The advantage of OAuth in certain situations is that you can basically get out of being responsible for holding user's credentials entirely. Let's say you're CircleCI or Travis or some other service like that - as long as you can build your product on top of GitHub, you don't actually need to store a user's login credentials yourself. It's still a somewhat complicated flow to have to put together, but your threat model on the other side is lower since you don't have to worry about being a vector for someone to try to steal the user's credentials.
[+] merb|8 years ago|reply
well basically OAuth2 Resource Owner Password Credentials Grant (https://tools.ietf.org/html/rfc6749#section-4.3)

Is basically the same thing than Login Form + Cookie, just that you return the Token instead of setting a Cookie.

So it's only more complex if you also act as a OAuth Provider, that implements all the other Flows.

[+] evfanknitram|8 years ago|reply
Cookies are a mechanism to store data in the client. Jwt token will still need to be stored somewhere (for example in a cookie).

To me, saying Cookies vs JWT doesn't really make any sense. It's like asking what is more secure, JSON or MySql?

[+] amend|8 years ago|reply
I just updated my question, as it was vague. I’d appreciate your input!
[+] JepZ|8 years ago|reply
First of all, that question is kinda weird as those three are not of equal type. For example, OAuth uses JWT and JWTs can be stored in cookies, but as far as I know they aren't normally.

The differences between classic a session ID in a cookie vs. JWT is more or less, that JWTs often hold encrypted session information (stored on the client), while the session ID is just a random identifier and the session data is stored on some server (so its easier to build scaleable solutions with JWT). Security wise you might be interested, that cookies are sent automatically while JWTs are not (unless they are saved within a cookie).

You might wanna read: https://stackoverflow.com/questions/37582444/jwt-vs-cookies-...

[+] kevlened|8 years ago|reply
Just to be clear, JWTs may be encrypted (JWE), but are almost always just signed (JWS). Don't store data you don't mind exposing in a signed JWT.
[+] clhodapp|8 years ago|reply
OAuth doesn't specifically call for JWTs. From OAuth's point of view, all of the tokens, codes, IDs, and secrets are opaque character strings.
[+] shiado|8 years ago|reply
Make sure you set HttpOnly for session cookies to eliminate XSS token stealing. If you use localStorage in an SPA for tokens make sure you set up the scope such a way to minimize XSS token stealing. Not sure how the rest of your app works but make sure you use some anti-CSRF library.
[+] sdfin|8 years ago|reply
This kind of question appears often here. I found the following discussion very informative: https://news.ycombinator.com/item?id=16157002 (as you can see, there are very different and conflicting opinions about what are the best practices).

I'd find it very helpful if somebody can recommend a resource, like some book, course or blog post that thoroughly explains the best practices and recommended strategies about authentication for APIs, websites and mobile apps in client/server and server/server communication.

[+] eranation|8 years ago|reply
These are three different things.

Cookies: a storage mechanism. If you use simple cookies (session GUID) for authentication, you must maintain state in some persistent storage to tell if a session ID is valid or not. httpOnly, secure cookies and CSRF protection are also required.

JWT: a digitally signed document containing claims about a user. Can be stored in a cookie or in localStorage or in your mobile app’s memory/temp storage. You can be stateless as the validity of the token is protected by its digital signature.

Oauth: a protocol for authorization. Can embed the authorization claims in a JWT token among other ways.

[+] venantius|8 years ago|reply
Haha, oh man I've spent a lot of time thinking about exactly this. I don't think I've got much to add that anyone else hasn't already said, but:

Cookies - well known, hard to footgun yourself

JWT - new, complicated to implement, easy to footgun yourself

OAuth - generally only works in certain security models. You're probably still going to end up using cookies or JWTs as part of your OAuth state management anyways.

Personally, I use cookies for all "apps" and I'll use JWTs when I need authn/authz in a more complicated microservice architecture where the "clients" aren't browsers.

[+] ukulele|8 years ago|reply
This is such a vaguely worded question and spec that I doubt you'll get anything out of it. All three are fine in the right context and not even mutually exclusive.

Maybe do some basic research first, then ask with more details on your setup and what is important vs not important.

[+] amend|8 years ago|reply
I just updated my question, as it was vague. I’d appreciate your input!
[+] nickjj|8 years ago|reply
I just use sessions, backed by cookies.

I find with JWTs you end up dealing with cookies in the end, because on browsers you're definitely going to want to persist the token in a cookie so the user can have access in between requests.

Also, for the apps I develop, I often need to request the current user from a persisted database, so I'm doing a DB lookup on every request no matter what. Sure, I could cache this request in Redis but even on apps that have had to do this hundreds of thousands of times a month, it never caused any performance issues reading it directly from Postgres.

[+] hacknat|8 years ago|reply
I’ve never thought of JWT as being something you would want to use in a unified application, it tends to shine in situations where one application is the authorizing agent for another application not totally in its control (e.g. private Docker registry auth). You can set expiry fields in JWT, so revocation isn’t the concern everyone is saying it is. Also, just because a form of auth is out in the open it doesn’t mean it’s less secure (TLS, anyone?).
[+] imauld|8 years ago|reply
> You can set expiry fields in JWT, so revocation isn’t the concern everyone is saying it is.

The issue with JWT revocation is if someone has a JWT that says they are an admin and then you make them not an admin or if an admin (or any for that matter) account is breached it's difficult to remove access from the attacker. With a session you just change the password and kill the session. This can be mitigated by short expiry times but a lot of damage can be done in a short amount of time by a determined attacker.

[+] therealdrag0|8 years ago|reply
Depends what your definition of "unified application is". If your application has many micro-services, then a single request from the outside could folk into many nested calls. JWT can benefit this by preventing each of these calls from making it's own external auth request.
[+] motohagiography|8 years ago|reply
If you needed to auth users on both a mobile app across platforms, and a browser, it makes sense to store and xmit user session information in a JWS or JWE, using it as an abstraction which you can serve as a cookie to the browser, and handle consistently across apps. If you get into multifactor auth, implementing it in JWT becomes more useful. A full OAuth provider seems heavy for what you've described.
[+] dwaite|8 years ago|reply
There are a few benefits of using something like OAuth even if you don't plan to open your API to third parties.

1. You may decide you want to have multiple first-party clients to your API. Examples would be a web site, a native client, a command-line app. OAuth lets all of these different applications call the same API once they get a token.

2. There could be security value in segmenting the user authentication into an entirely separate app with its own database - it greatly reduces the attack surface which could be leveraged to get your user credentials to attacks against your user authentication (and likely registration) app, vs your entire website and all your APIs.

3. If you decide to open up your API in the future, you have already done a significant amount of the architectural legwork.

4. If you decide to support social logins (Facebook or Google for instance) in the future, you can do so just at your personal OAuth authorization service. Your apps don't care how they get an access token, and your APIs are still getting a local access token that they understand (rather than trying to understand Google or Facebook tokens).

[+] Lazare|8 years ago|reply
> I’m using sessions/cookies for keeping state and keeping the user logged in

Good. Sessions are the standard for a reason, and it's currently considered best practice. And if you've got a session ID, and your clients support cookies, then sure, use cookies for storing them.

> will using JWT (with the token stored in the cookie) to keep the user logged in instead of sessions/cookies make my application more secure

No. Probably less secure, although if you know what you're doing you can mitigate the issues. But certainly not more secure.

[+] fimdomeio|8 years ago|reply
There are situations where you can't use cookies like when developing mobile apps [0]

[0] https://stackoverflow.com/questions/31139365/can-you-use-coo...

We only stoped using cookies because of that since we wanted a more universal implementation so minimal changes had to be done between a web app and a mobile app implementation.

Other than that we would keep using session cookies.

[+] nethsix|8 years ago|reply
For your case, you do not need JWT.

Stateless JWT is useful in the scenario where one server is capable of authenticating a user (through password, social login, one-time password, etc.), and a different server holds resources that the user is trying to access.

The server doing the authentication will issue a stateless JWT with all the user credentials cryptographically signed, so that the user can pass the JWT to the server holding the resource to be granted access, assuming that server trusts the authentication server to perform authentication correctly.

Stateless JWT is useful here because the server holding the resources can verify the credentials of the user without contacting the authentication server.

Regarding OAuth, there are 2 sides to it. You can become an OAuth provider, which I reckon you are not interested to be. What you may be interested is to use OAuth to enable users of OAuth providers like Facebook, Twitter, .etc, to access your service, so that you minimize what you have to develop in terms of user management, i.e., you don't have to worry about user creation, email verification, password resets, etc., because all those have been performed by the OAuth providers.

I believe passport.js allows you to use OAuth to allow OAuth providers' users to access your service. passport.js may be a backend-base solution so you have to be somewhat familiar with OAuth to get started.

Alternatively take a look a https://oauth.io, which has a front-end based solution; I am not saying a front-end based solution is better, but rather it's easier to understand for someone starting out. Moreover they have JS fiddles that you can instantly play around with.

Check out the JS fiddle for creating a 'Login with Github' for your website here in just a couple of lines of Javascript: https://jsfiddle.net/dg9h7dse/1/

There is a full explanation of what the code is doing here: https://coderwall.com/p/sjbwcq/javascript-github-social-logi...

[+] borplk|8 years ago|reply
Cookies have some excellent security features ("secure" flag, "http" flag to prevent javascript from acesssing it, and "same-site" flag for CSRF prevention on modern browsers).

Don't use other storage mechanisms for storing anything secret. Nothing beats cookies today.