Hacker News new | past | comments | ask | show | jobs | submit login
Ask HN: Cookies vs. JWT vs. OAuth
260 points by amend on March 4, 2018 | hide | past | favorite | 93 comments
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?

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_(...

> "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.

Absolutely. Though, when people say cookies vs JWT, what they mean is:

Cookies: a simple session ID, a random number, stored in a cookie.

JWT: a JSON object stored in local storage that specifies authorization of some user that is authenticated by public key cryptography. JWTs can be configured in many ways, but this is what people usually mean because they want their sessions to be "stateless."

Way way more often than not, the "cookie" solution is better because it's far simpler. JWTs come with a tremendous amount of complexity with few benefits.

My big issue with JWTs: securing images. With cookies, a browser attaches the cookie on the image request. With JWT, a browser does not send it with the request. Cookies are far easier in this case.

> With JWT, a browser does not send it with the request

Sure it does, just put the JWT in the cookie ;)

JWTs are small enough that they can fit in a URL most of the time. So there's always that option.

I believe it is generally considered unwise to attach your authentication token to the URL, as it's highly likely to end up in a bunch of access logs.

If the token is only good for one use or for a short period of time (minutes not hours) it's probably fine. I've used them in URL's for invite links. One time use that expire after a short amount of time. Probably not perfect for high security applications like banks or health care but for most applications it's fine.

This was what I was about to post -- JWT-in-cookie is just about perfect from a security/convenience ratio standpoint is it not? Assuming the HTTP cookie is secured properly (like all cookies normally are), it's the perfect way to serve both browser and non-browser traffic (apps may choose to do a little more work to pull the cookie out of the authentication request and use just the auth header if they want).

Any thoughts? I can't think of anything glaringly wrong with the scheme.

Also, I generally think that if someone has the resources to obtain your JWT it probably doesn't matter if it's encrypted (assuming it's stuff like the user's ID or roles, and not something you shouldn't be putting in there anyway), because the attacker has the time until you revoke the token to do whatever they want as the user.

I'd love to hear why I'm wrong

Sorry for the curt reply, I'm about to fall asleep.

In OP's case, I think they're unlikely to see any benefits to using JWT.

Dealing with authN/authZ can grow fairly complicated depending on the business' requirements. On the surface what you're suggesting seems like it would work perfectly fine for many use-cases, so you're not wrong.

JWT is often immaterial to authentication. One must consider how the service is consumed and through which mediums. Depending on the data's importance, you'll need to carefully consider the security model.

Acquiring someone's cookie or token doesn't always mean full access, nor does it mean you get to repeatedly request new tokens. You could require an additional password check before allowing the user to take certain actions. Two examples of this are GitHub and Google.

Absolutely -- In the end to even invalidate a JWT properly you have to either depend on time (so short-lived tokens + refresh token), or store some sort of blacklist (and then you're back to where you started anyway). The world is probably ready for a microservice that does this that everyone can use -- I saw one on HN a while ago but haven't seen it since.

The big benefit I saw from JWTs was the stateless nature, with the drawback of servers using the same key.

Thanks for the reply! Sleep well.

OP is not familiarized with the topic, and was probably confused and overwhelmed. Not surprising, as getting authentication right can be very challenging.

I told them to avoid JWT and instead use old-school stateful session cookies because there's tons of libs that do most of the work for you, and they're unlikely to see any material benefits at this time from using JWT.

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).

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).

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.

Ok, good - thanks for confirming that. I haven't had to implement Oauth2 quite yet but that was my impression from reading what needed to be done, but that impression was at odds with a lot of internet rants.

> 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.

Which is probably the most robust and scalable of them all. I was wondering some some services took 30m to an hour to revoke access, and this is the reason why. Only downside is you have to use JavaScript on the browser, which isn’t much of a problem really.

You don't specifically need JS here.

Any endpoint could automatically update the user session token when it detects it's about to run out and update the cookie that it is stored in.

Oh right! I totally forgot that you could use cookies for JWT. It's been a while, but I think the reason why I didn't think of it was because, if you're using cookies to transport jwt, couldn't you just use signed cookies with a set expiration date?

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.

If OP isn't allowing third parties to authenticate through their API there's really no reason to use OAuth.

To echo a sibling comment [0], if you don't use OAuth2 (or the OpenID Connect profile), you'll end up reimplementing similar functionality. There are libraries for OAuth2/OpenID Connect, while a custom authentication strategy requires more effort.

[0] https://news.ycombinator.com/item?id=16519660

Why not tokens? They're easy and work well with an Authorization header on mobile.

I'd argue that they can also be implemented in a much more lightweight fashion than having to go through a whole OAuth flow just for a mobile app that hits an API that you control completely.

Then you have to deal with password resets and account creation, which if you know how those work, don't really sound all that lightweight compared to OAuth 2.

I'm not sure what you mean. The OAuth2 spec defines access tokens and also specifies that they should go in an Authorization header.

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.

Having a blacklist is probably still preferable to storing every session though in that there should be less data stored, if only marginally

I just updated my question, as it was vague. I’d appreciate your input!

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.

> 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.

Yup, this board is full of JWT hate mostly predicated on the fact that it can be done wrong. Just use a random token as a session ID. Wrap in cookie for browser users and use browser session cookie expiration. Wrap in JWT and sign an expiration date in there for API use...no other state needed, use token to look up actual valuable state on server side as necessary. Expire them server side too based on application re-login requirements to prevent reuse (or sign your cookies w/ an expiration date like you do with JWT...but I always keep session tokens and expire them on the server side too for various reasons including auditing purposes).

And what does that give you over just using a cookie?

Sometimes you don't have cookies? Like with mobile apps. With JWT you can also have uniform auth across mobile and web apps, and when done right is a beautiful thing™.

Also cross domain/app data signing.

> Sometimes you don't have cookies? Like with mobile apps.

A cookie is just an HTTP header. Any mobile app that can speak HTTP can use cookies.

> What a flawed argument,


> session revocation, even in an async stateless jwt context

> blacklisting

But isn't blacklisting stateful in its nature and thus achieving the opposit of what JWTs are for? Am I missing something obvious?

There's always state. Stateless is a misnomer, in much the way that serverless is a misnomer. It typically indicates the state information is passed inlined with the request.

When you inline the state in a cookie for "stateless" operation, you are essentially operating on a (hopefully cryptographically secured) cache.

Revocation is thus a cache invalidation, and requires its own state. When revoking from a database or memory, you can simply delete or mark the record. When revoking cookies, you are going to build that state mechanism as a blacklist.

This is why OAuth lets you have both access and refresh tokens. Your access tokens can have inlined state with a short duration, such that an API can service a request without having to be bottlenecked in a database or API call against an authoritative source.

However, when that access token expires (say, after 10 minutes), the API will stop accepting it. That is when you have to use the refresh token, which goes back against the authoritative source.

You lose the immediacy of a blacklist, but you don't have to have that state distributed across your infrastructure. You instead wind up pushing the effort to keep up-to-date tokens onto the OAuth clients.

I think you have this right. This was also my experience with JWTs - go far enough down the revocation rabbit hole and it seems you just end up with a stateful solution again, but just with a more complex and expensive token verification mechanism (compared to just equality checking the token value). At that point, it really seems pointless.

>you just end up with a stateful solution again

It checks the "stateful" box in a nominal way, but it does not have the drawback of stateful session cookies that "stateless" defines itself in comparison to: in the backend, the session is still not in-memory or in-db on a single machine.

So you don't really go back to "stateful" except nominally; a very large part of the scaling benefit remains.

Let me be more concrete, maybe it will illustrate the point I'm trying to make better and/or highlight some aspects I'm wrong about.

I'm aware of broadly two schemes for revocation support with JWT:

1) Immediate revocation - keep a blacklist in state on a single machine. On verification of the JWT, check the blacklist and only succeed if it is not present.

2) Eventual revocation - keep a renewal token in state on a single machine, and give your JWTs an expiry time T. On verification of the JWT, if verification fails due to expiry then try to renew the JWT using the renewal token, and if successful then succeed the verification and also return the new JWT to the client. To revoke the JWT, just revoke the stateful renewal token. The JWTs can therefore be revoked eventually within a max time of T.


So, the above Vs the classical stateful session token (from here SST) approach:

Both 1) and 2) contain the same 'single stateful machine' limitation as SST, yet are more complex to understand, reason about and maintain.

In 1) you get no additional benefits over SST, and you have completely nullified the statelessness and therefore scalability of JWT. You also get the additional downside of a more computationally expensive token verification than just a simple equality check.

Conclusion - it seems irrational to use 1) over SST in all cases.


In 2) you get precisely one potential benefit for scalability - that for a time (max T) you get a stateless 'cache' for the verification of the JWT, which will horizontally scale to infinity. This MAY give you some practical benefit at massive scale, but there are two significant downsides:

A) You have a max lag T on revocation of the JWT, which is a security hole if the JWT is stolen. So you'd like to minimise T - but not so much that you lose the benefit of the 'cache' - otherwise the whole thing is pointless. You have to literally trade off security for scalability! Where do you draw that line?

B) The whole system is very much more complex to operate, debug, and reason about, than SST. You have verification logic that is split across 1 central stateful renewal token server & n JWT verification servers.

Conclusion - the scalability gain of 2) comes only as a trade off against security. Even assuming you are able to accept this trade off at all it is really unclear to what extent you should do so, and indeed if the whole complexity of the thing is even worth it after all that.


Perhaps there is another way to do revocation of JWTs that I've missed that is clearly superior to SST, maintaining stateless verification without any clear security trade offs. If so please educate me - I would love to discover it!

Otherwise, I concede that scheme 2) might be a better option than SST in some very rare and special cases, but in general if revocation is needed, then JWT does not make sense in place of SST.

I'm using JWT for auth on a microservice so that it doesn't have to phone home to authorize requests. For revocation, the user service pushes the revocation to the microservice, which maintains its own blacklist. JWT works great for us because it contains all of the identity necessary for auth decisions on the microservice. An opaque token would require the microservice to phone home to get a user's identity data.

I appreciate the effort you put into writing your response. You make a very solid case and I wouldn't attempt to talk you out of using SSTs over JWTs given the level of consideration you've put into it.

I would nonetheless offer the following points if you'll excuse the rambling:

- I concede that the following probably exposes a lack of knowledge on my part. I think most, myself included, don't have a 100% lucid understanding of how session cookies are managed throughout the stack. It feels like there is some degree of idiosyncrasy and magic at every level, e.g. client -> reverse proxy -> application backend (-> potentially DB) while JWT feels much more lucid and consistent in this regard. It seems desirable and simpler to want to transparently pass through all the "smart" layers that have explicit knowledge of and opinions about session cookies.

- JWTs come off less "magical" than session cookies and I find them just as easy, if not easier to reason about in certain situations, e.g. in an app rather than in a browser - I'm aware that cookies are mere headers, but I still find that slightly more annoying to manage than JWTs - although I concede that perhaps this is merely due to the availability of libraries that make it so, while also not being too "magical" and hiding key parts of the flow (whereas various platforms e.g. ASP.NET, PHP do weird magical things with session cookies).

But, you know, your post is making me have second thoughts about my position here, and I may yet be won over after thinking about this some more. I think this is often an underrated and unnoticed point - that there is some a priori magicalness about session state, while JWT is simply presented less magically, and so one may be attracted to the initial lucidity of JWTs vs. having to learn session state (because "why haven't I learned how automatic session management works after using it for all these years? It's probably very hard"). And I'm beginning to realize choosing JWTs for this reason may be specious.

- I find, in practice, that a JWT workflow's blacklists are still a lighter level of statefulness than having to propagate user sessions. As you rightly state, this comes in the form of eventualness, and it is indeed a security tradeoff. Here, perhaps my imagination (or experience) is lacking, but I estimate that it would in practice be difficult using SST for 1. To have a token theft; 2. To detect said token theft; 3. To implement security measures; in less than the time of JWT revocation.

- I obviously find that JWTs make more sense than session cookies in RESTish APIs, in which the desired workflow is modeled after HTTP and does not require a session on the backend (so the statelessness is not just for scaling). It's certainly a good thing to have a standard for passing a verifiable proof of authentication inline with every request.

> "But isn't blacklisting stateful in its nature and thus achieving the opposit of what JWTs are for?"

JWTs are really just the format, and you can store them however you want to.

What you want is to avoid having to query a centralized database or datastore for every request. (1)

It's hard, but doable, to design a blacklisting scheme that does not depend on a centralized db (2). This way you can have your cake and eat it too. You avoid the "ask the database for every request" scenario. People will counter with "but you query the database for every request anyway" to which I answer: "No, I do not" :)

1: Well, that depends on your app and usecase, of course

2: Basically you push the blacklist, which is short, out to everything that needs it. It gets complicated =/

JWT's are just special signed formatted strings with a couple of dots in the middle. I only use them for API tokens, and I don't use them statelessly, I just use them so the client knows the format and can check expiration inside it. Sure many use them to pass around signed state, but that's a choice. They're just a container for a stateful session ID for me.

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.

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.

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?

I just updated my question, as it was vague. I’d appreciate your input!

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-...

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.

since i was looking into GDPR, a JWT token containing signed data may potentially be a source of private data (i.e., you store the username there), and therefore, have to have a way to clear it, and/or ensure that it is encrypted in transit.

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.

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.

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.

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.

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.

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.

I just updated my question, as it was vague. I’d appreciate your input!

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.

I found this to be a great resource when groking your question recently


Also this previous HN thread https://news.ycombinator.com/item?id=13865459

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?).

> 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.

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.

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.

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).

Don't use JWT or local storage for storing sessions. It's pointless/potentially less secure. Just use sessions and cookies.

Here are some good blog posts that explain this better than I can (the flow chart in 3 is particularly illuminating):

[1] https://paragonie.com/blog/2017/03/jwt-json-web-tokens-is-ba...

[2] http://cryto.net/~joepie91/blog/2016/06/13/stop-using-jwt-fo...

[3] http://cryto.net/%7Ejoepie91/blog/2016/06/19/stop-using-jwt-...

> 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.

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.

Not familiar with the framework referenced in your link, but if you are doing truly native development on iOS, the URL loading supports cookies [0]

[0] https://developer.apple.com/library/content/documentation/Co...

Cordova wraps a web app into a native container. I've never used it, but i guess it doesn't use (or expose?) the native loading API…

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...

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.

A related topic that you might find interesting:


I've worked with Macaroons (writing custom tools and libraries) and Macaroons are definitely more complex than JWTs. Don't be fooled with one signature algorithm, there are more things hidden under the surface (e.g.validation of a set of Macaroons requires finding cycles in a graph and symmetric decryption of data). If you really need tokens use constrained JWTs. Better: just use random strings.

Some thoughts on when it's ok to use JWT https://techblog.bozho.net/using-jwt-sessions/

JWT's are stateless and cookies are not, you can achieve the same thing with cookies as with JWT if you store your sessions in redis etc.. for api's I'd recommend JWT's.

I just updated my question, as it was vague. I’d appreciate your input!

As long as you protect against CSRF attacks (I do not know anything about passport.js), cookie authentication is okay provided the API is not going to be consumed by external sites.

Using cookies with Domain option allows you to share a cookie between `api.site.com` and `www.site.com`.

You can combine that with a `Authentication Bearer` for releasing a public API access.

JWT is more a "lingua franca" token since it is not binded to a "http context", but in the end, cookies and jwt tokens or any other kind of authorization tokens are simply a way to identify a user. As i told you before JWT tokens are more loosely coupled to http request than cookies so they may be a best choice, especially if you plan to build stateless apis. The only strictly important rule is: do not store any sensitive informations on client side data structure since you can't trust the client side.

> do not store any sensitive informations on client side data structure since you can't trust the client side

Except that the tokens are cryptographically signed, so as long as you verify them, you can trust them.

These three concepts are largely orthogonal, but pair well.

Cookies are a state management system for HTTP, which is normally stateless. Rather than representing state via data embedded in the URL or requiring intelligence in the HTTP stack to represent that state in application-specific headers, Cookies allow the server to set state on a response which will be returned on subsequent requests. The browser doesn't need any special rules behind the generic cookie retention rules.

Cookies can be used for any sort of state, but in this context you probably care about authentication/authorization state. Nearly every website which uses a web-based authentication flow (including OAuth and OpenID Connect) winds up using cookies to track authentication state.

OAuth is a HTTP-based framework for providing delegated authorization. Rather than sharing user credentials with every piece of code which may want to access resources associated with a user, the Authorization Service handles authentication as well as user consent to let a client act on their behalf. While there are several flows to account for different application requirements, this eventually results in an access token, a usually time-limited value which represents access to just the capabilities the user consented.

Facebook, Microsoft, and Google all use variants of OAuth to share user authentication as well as provide access to user information and API access to user accounts. There are challenges to OAuth interoperability, with many deployments adding additional capabilities outside the specification (such as representing user authentication). Facebook has their own extensions, while Microsoft and Google support the more standardized OpenID Connect as a interoperable profile.

Since the access token is state, there is nothing forbidding it from being set as a cookie. However, anyone who can get this token can perform actions as the user (bad) as your application (from a purely selfish perspective, worse). Many server-side web applications which store access tokens will either store them in a database and reference the row in a cookie, or store them in an encrypted cookie to prevent them from being extracted and used externally. One way to store such data in an encrypted cookie is via a JWT.

A JSON Web Token is a data format defined by the OAuth working group. Access tokens are really messages for the "Protected Resources" in OAuth parlance - typically API endpoints. However, the core specification did not define any format for these values, leaving them deployment-specific. JWT was an attempt to provide a good recommendation for the format, and was also designed to be leveraged by OpenID Connect (which both extend core OAuth with new functionality and provide an interoperable profile of usage).

It is typical that since security is hard, formats that take security into account (such as JWT) wind up getting both overused and oversold. People want to be able to say things like "our authentication is secure because we use JWTs", but instead statements like that are usually a red flag that the system was implemented by people who did not understand the overall security requirements.

No, it won't be more secure, just less standard and possibly more difficult to work with.

If I am implementing just a backend API, what security strategy should I follow?

> but will using JWT to keep the user logged in instead of sessions/cookies

You can't use JWT without cookies, or local storage (which is effectively the same here), so that makes no sense.

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

You're still so vague that it's hard to answer. If you want to authenticate them, you can use OAuth. But no, it's not necessary to authenticate them with any one auth service...

I updated my question so it’s more clear. The update is relavent to your first point.

By local storage do you mean storage on the client or server? I thought a benefit of jwt is not having to store anything on the server, is this correct?

"Local storage" is the name of something most web browsers implement https://www.w3schools.com/html/html5_webstorage.asp

That's not really a benefit. If it's on the server it's far more secure, unless you've messed that up, and you have less/no issues with running out of space on the server.

Applications are open for YC Summer 2023

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact