Guardian/JWT vs Phoenix.Token?

In most cases, you’ll probably fetch the user from the database anyway, right? So, what’s the upside of this compared to just a raw token in the DB that you change on each logout/password reset etc?

The only upside I can see is that you don’t need to fetch the user for 5 minutes. Essentially you’ve built a cache :slight_smile:

3 Likes
  1. Using JWT tokens for browser sessions seems moot, because if you are storing a jwt token in the session you may as well store the user_id and make things simpler. If the session storage is cookie based, it is still safe because the cookies are signed and phoenix will blow up if you tamper the cookie.
  2. Using JWT tokens for API access seems reasonable, However, you don’t get the flexibility to invalidate them.
  3. Some people store the JWT token in a database and return another uuid which lets you look up the JWT token, this completely defeats the purpose of JWT.

Like the blog article linked above, I think JWT makes sense when you have 2 independent applications which need a way to authenticate without talking to each other. It makes more sense if you use public keys on sending server and the private keys on the receiving server for authentication.

4 Likes

In most cases, you’ll probably fetch the user from the database anyway, right? So, what’s the upside of this compared to just a raw token in the DB that you change on each logout/password reset etc?

If you make the assumption that every request is going to necessitate database interaction, particularly with a user account record, then yes, I don’t think it buys you anything. But examine that assumption. Why do we go to the DB for state on every request, even when it doesn’t change from one request to another?

What if instead the database was used to shadow the active state of your application? Your state is held in memory in genservers, and while writes are sent to the database, reads are independent of it. Read in the state to init the genserver, but not on every request. Then your transient bits of state like nonces/auth tokens can live in a more transient location.

Its certainly not the only way of doing it, and isn’t appropriate for every application. But particularly when web development has been steeped in the use of ORMs and the use of relational stores as an integration layer between applications and stateless servers, its worth reexamining the assumptions that we’ve gone with for nearly two decades in the face of alternatives which are just as viable, if less familiar.

1 Like

I haven’t used eternal, so I can’t answer that question. Let me know how you get on and if you have any feedback.

1 Like

You’re obviously right, and I know nothing. Do you feel any better now?

I don’t think he meant any disrespect to your work in any way by his comments.

Moving forward…
What is the best way to go about revoking jwt’s on pure API based applications serving mobile apps? Is there a right and wrong way or you probably go with what works even if that means “hitting the db” once in a while?

I believe security is fundamental and should not be an afterthought at the expense of being a purist. What are your thoughts?

If I am getting it correctly, this means it’s probably not a bad idea to throw in a db check in there if it allows you to validate and by extension secure your app ‘better’ :slight_smile:

Sorry if I offended you. It seems like you misunderstood me somehow. In my response in the last paragraph I meant “you” as in a general you, not you specifically. I have never looked at OpenMaize or anything you’ve done. I’m sure you are very knowledgeable and have good insights that would be beneficial for this discussion.

I have never used JWTs but I’m trying to learn more about them and the correct way to use JWTs. I think it’s important to understand and not just cargo cult.

Also, what I wrote are just statements that I’ve come to believe to be true about JWTs. I want them to be challenged. Please let me know if they are true or if I’m totally lost here. Any feedback is appreciated! :slight_smile:

4 Likes

The first question is whether you need to revoke the jwt at all - in many cases, it might be enough to just let it expire. With many apis, there isn’t really a logout functionality - the user will just access the resources he / she needs and then stop using it.
If you do want to revoke jwts, I know that many developers use Redis for this, and that might be quicker than a db lookup.
With openmaize_jwt, you can use the store_jwt(token) and query_jwt(token) functions in the OpenmaizeJWT.LogoutManager module to handle this.
If you have any further questions, please let me know.

1 Like

It seems like there was a slight misunderstanding there :slight_smile:
To find out more about the differences between traditional cookie / session authentication and JWTs I think this link can explain it better than me. It’s important to know that the advantages might not be that relevant for you, depending on the nature of the app you’re writing. For example, the fact that you save a database lookup is meaningless if you’re then going to consult the database (to get more data) anyway. From my point of view, as an authentication library maintainer, it looks like JWTs are generally the more favored (future-proof?) option.
On the subject of logging out, the first thing that happens with most implementations is that the JWT is deleted - if it’s stored in a cookie, the JWT can be deleted on the backend, and if it’s stored in local storage, it needs to be deleted on the frontend. The next thing that some implementations do is try to guard against an attacker using the same JWT to gain access, by having some kind of blacklist and invalidating the JWT. This can be done by checking the database, and I know that some implementations use Redis to keep track of these JWTs. With Openmaize (and OpenmaizeJWT), I’m using a genserver to maintain this blacklist, and it is checked every hour and expired JWTs are removed, so it shouldn’t get too big (let me know if you want me to explain this in more detail).
The last thing to mention about logging out is that depending on the nature of your app, ‘logging out’ might not be that relevant - the user will just access the resources and then stop using them, after which the token will eventually expire (usually after 1-2 hours). There probably will still be a need for maintaining a blacklist, but in this case it would be for compromised JWTs.
If you have any further questions, just let me know.

2 Likes

Makes sense. I’m still experimenting with JWT. On Hackernews there are also some interesting discussion the last week.

For example: https://news.ycombinator.com/item?id=11929267

2 Likes

Hi, author of the “don’t use JWT for sessions” article here.

I would take any articles from Auth0 with a grain of salt - they appear to have some vested interest in recommending JWT, and seem to spend a considerable chunk of their blog posts on recommending it in various ways. JWT tokens are absolutely not more future-proof than sessions - they are a different solution for a different problem. Implementing a blacklist system isn’t really a good solution, either - I’ve covered that in my follow-up post.

Similarly, storing it in Local Storage is just never okay, as it will open you up to session stealing. This is a problem that (HttpOnly) cookies do not have.

The summary is that there are no usecases where JWT are a good option for sessions - the only case in which it’s a valid choice is if you are scaling up so much that you just can’t have a centralized session store. It’s still not a good option, but stateless JWT (or similar stateless token schemes) are pretty much just the only option you have left.

EDIT: Of course, if there are no well-tested session implementations available for your stack, then a stateful JWT token can be a useful way to implement signed session IDs. But you’d still not store the actual session data in the token.

4 Likes

Thanks for posting, certainly some interesting reading material. Quck question: is storing sessions in any way on the client not a bad idea, and not JWT specific?

First I though that sessions were not needed when communicating with a JSON API from a mobile app. But after further thought, a authorized user can be considered a logged in user, and I guess this can be considered a session if you also want tog-out an user. It has a logged-in state.

So storing a signed session id in a token could be a way to go. On every request you would retrieve the user data linked to this session id from a fast database (for example Redis) and continue.I think this is already a widely used pattern.

Any Elixir specific implementations that would add value as an Redis alternative?

  • GenServer;
  • ETS,
  • DETS,
  • Mnesia

Thoughts?

1 Like

An older article discussing session storage in cookies that might be interesting:
Why you probably shouldn’t use cookies to store session data

I would say that storing session data on the client side is always a bad idea, for the reasons already outlined in the article you referenced. That having been said, there are some edge cases where - despite it being a bad idea - it’s still the least bad idea; in particular, in highly scalable setups where centralized session storage is just somehow not viable.

Very few people run into those situations, though, so I’d strongly recommend against building something like that as a general-purpose solution, and would argue to leave it a specialized option instead.

Storing a signed session ID in the cookie, using centralized session data storage, is definitely the way to go for a generic implementation. Redis is a fairly widely used option, but not necessarily the only good one; any kind of store can work, really, and if you are already using a database (such as PostgreSQL), then it can be desirable to store sessions there as well - at least until scale demands otherwise. The less moving parts you can get away with, the better.

I wouldn’t have any Elixir-specific recommendations, personally; I haven’t actually used Elixir (yet), and I just ended up here after checking the referrers for my article. It’s a useful approach to addressing questions and misunderstandings across the web :slight_smile:

3 Likes

Interesting. It seems then that the cookie approach in Phoenix is not ideal either where user specific information is stored.

So I’ve looked into it further and are still exploring the best options. I’ve looked into the signed session id approach.
For my hobby project I’m working with a JSON API, and cookies are not really an options. Taking into account that a JWT signs it claims, isn’t this almost the same as a signed session id? Of course, now it’s up to the developer to store nothing else besides the sessionID.

To invalidate JWTs, people use one of two methods

  • a blacklist
  • a refresh token (which allows regenerating access tokens) with a short expiring access token.

In a general way, there are pros and cons to pretty much every approach to authentication. JWTs make it easy to do some things (client side auth, SSO, serverless apps), and harder to do others, like invalidation. Would recommend reading the HN discussion ( https://news.ycombinator.com/item?id=11895440) around the critical article that was linked to in this this thread

2 Likes

I dont think that link applies to JWTs for the following reasons

performance: JWTs are not for storing all session data, they are for authorizing a request, so they wont have the same size characteristics that signed cookies do. Also, JWTs can be sent as request headers. If you have a single page application, you can choose to not store them in the cookies.

security: i have yet to work on a web application that didnt have dozens of secrets that needed to be kept out of source control and managed on servers. Your JWT private key is just another one.

Would also point out that pretty much every major tech company uses bearer tokens (facebook, google, microsoft, etc) which are very similar in concept to JWTs. Not saying that automatically makes it a good idea for you and your app, but in a general way this is a well vetted idea.

In my post i’m offering to only store a session ID, nothing more.

I have used both methods in the past and they do work (with their tradeoffs offcourse). But creates it’s own problems (as pointed out here.

a blacklist → why dont store sessions serverside? Isn’t this alsmost the same,
refresh tokens → what if you want to revoke this token for a specific user?

1 Like