I have always opt for having jwt over session because of the less over head in the backend side (keeping in mind that it all depends on the use case) but the major issue I am having with it is the invalidation of the token, for an example : in case of the user being deactivated, the relevant jwt would still be valid until it gets expired. Is there anyway to overcome this issue in a cost effective manner ?
PS - however I saw the term " revoking JWT " in the cookbook section on the featherjs
framework. but its still looks like they are using redis as a lookup which in turns make it inherit drawback of using sessions.
Once a JWT is issued it is valid for as long as the exp claim value. You can't revoke a JWT, it's not how JWTs are meant to work.
As you pointed, out there are ways of mimicking the behaviour of revocation, but you need two things for that:
you need to have a database with information about which tokens are revoked
you have to make sure that whenever you consume the token you check online with the database.
There is no other way to do that.
If you really have a need to revoke JWTs it means that you need sessions, and you shouldn't be using JWTs for that. You can have a look at this article to learn why. If you decide to stick to JWTs, have a look at this best practices article I wrote to know what to watch for.
Related
Implementing a login flow and have been persuaded by JWT's because we have scaling as priority.
In the past, the system would be based on session tokens in a monolith application. JWT's mean we don't need to have a caching server for user sessions anymore apparently. So then here's where I am confused:
If I get round the issue of revocation and token stealing by keeping a blacklist of keys (is the suggestion) then that now looks from above exactly the same thing as session tokens, because I'm doing a lookup with every request.
Perhaps I am not fully appreciating something or thinking of this wrong.
Perhaps - the result of not finding the blocked JWT is faster than a full retrieval.
Thanks for anything that would clear this up :)
If you implement a feature where you keep a blacklist of tokens then indeed this does not change much from a session. You still need to lookup the token, keep the blacklist updated, properly replicated, etc.
What might work better is to have access tokens with a very short expiration time, like 5 or 15 minutes. A time short enough that you can accept the risk of someone stealing the token and using it for this short time. Then you can only keep a blacklist of refresh tokens, which are used less often.
Our system architecture is like an admin can assign permissions on the user level. we are using JWT token for authorization, previously we use roles, and roles are added in payload on sever side we check that role and allow/disallow accordingly without hitting the database. But when we add permissions in the JWT token its payload is too heavy and affects the network traffic.
So my question is what is the best practice to deal with user base permissions in JWT token.
I don't think there is a "best practice" for this as it doesn't sound advisable to store a user's permissions in a JWT, because of the following:
Since a JWT must contain all the information necessary to execute a request, if at any given time a user has permissions removed, he will continue to have them for a period of time as long as his JWT has not expired. That is, using the approach you describe, adding or removing permissions from a user is not an effect that occurs immediately, so it is necessary to develop mechanisms so that the effect of those changes is immediate. Additionally, I consider that a user's permissions can be classified as sensitive information, and it is not recommended to store sensitive information in a JWT (since anyone can see it).
If you want to continue doing that, you can assign identifiers to permissions (such as small numbers) and store those identifiers and permissions in your server's RAM (for example, using a dictionary or hash table). Finally, in the JWT you only have to store the identifiers of the permissions, thus saving as much space as possible. This way there is no need to hit the database.
You really have two options if you are using JWTs and not some sort of session-based old framework.
You store permissions in the JWT. As pointed out there are 2 main issues with this. Firstly it becomes stale, possibly quickly. Secondly this potentially bloats the JWT depending on how many permissions you have in your application. Also, for multitenant applications you now make it significantly more awkward to switch between tenants on the fly. Because now you need to reissue a token (somehow force a logout/login) whenever the user changes tenants.
You handle permissions through a network call to a server (probably the login server) which remotely handles authorization. This adds overhead but keeps things responsive. The only downside is really network traffic. It may sound like there's ways around this but there really isn't and people have accepted the large amount of added traffic.
IMO do what is the least you need. There are bandaids for JWT staleness such as short refresh timers. There are also ways to work with bloated JWTs such as strings created from enum flags. If you do not need immediate refreshing of permissions or lots of them there is nothing wrong from a practicality standpoint of putting authorization data in the JWT.
If the above does not apply, then you need to setup a network call system to handle the authorization. Ideally this is faster/leaner than http network calls.
As an example I use gRPC calls. Example working repository you can see/run is at https://github.com/Perustaja/PermissionServerDemo
In my project there's a requirement to invalidate all jwt tokens of a user when the user changes his password. I was thinking of giving each user a different signing key, and simply reset the key when password is changed. Then I googled around and found Redis is a good place to store those per-user keys. Everything seems to work just fine.
But there one thing I cannot get my head around. Since it has to hit Redis once per request, is it any different than issuing the user an opaque token instead of JWT, and store the token -> JWT payload mapping in Redis?Isn't that defeats the purpose of using JWT?
To invalidate tokens you need to revoke them. OAuth spec also does not require getting secret key from remote server every time you need to validate JWT (as you said it kind of defeats the purpose). The key can be stored locally at resource site.
You have two options here:
1) Introspect the JWT token from resource side against OAuth server every time it validates it. Seems like overkill to me. The best approach is to give short expiration time to JWT token and let the already issued tokens to just expire.
2) Have the resource store the secret key locally and when it fails to validate go and get the key and re-validate it again.
From the point of view of invalidating the token, there's no particular need to store the JWT in Redis - anything that you can check and later invalidate should do the trick.
That said, presumably you're using a JWT for other reasons. For example, it's what the AuthN/Identity service provides. Or perhaps you use it to store claims or other metadata that you validate as part of the AuthN/AuthZ logic. In that case, since it's handy, storing the JWT seems very reasonable.
I'm looking at building a set of services that require an auth system but ideally I'd want them to be able validate these tokens without hitting a central auth service to check for every request.
Are there any known ways of doing this, better than something like a signed expiry-stamped permission enumeration?
JWT should suit you well, but it is actually a singed (or also encrypted if you need), expire-stamped list of data.
Keep in mind that there is no way to revoke (logout) such stateless tokens, what, depending on situation, might be a non-issue or a complicated problem to solve.
I have started to design a RESTful API and I'm thinking about how to handle authentication. I want to use some kind of authentication token but I can't use OAuth o similar infrastructures so I have to handle it myself.
One of the requirements for this API is that it must have good performance, enough to handle a high volume of requests before there is the need to scale; my concern is how to make on each request the time needed to verify the token (integrity, expiration, IP Address, etc...) as little as possibile.
I suppose the token should some kind of hash and not an encrypted string containing the user information because the decryption time would be to heavy.
I've read that I could store the tokens in an in-memory hashtable where the key is the token and the value is the user info needed to process the request, but how can I make this work in a clustered environment where there will be an hashtable on each "node"?
Should I put tokens on a DB table an hit the DB every time also Handling manually the retention of expired tickets?
Probably it's not that important for the question but I'm using Spring MVC for the RESTfull API.
Thanks in advance.
I solved my problem by using both an in-memory cache and a db cache. Here is a summary of my solution that may help anyone with the same task.
the user logs in and in that moment a unique key is generated and sent back to the user.
that login token (which is basically a GUID with some processing) is also store in a db table with additional info like exipiration and with the user's info and roles. the same pieces of information are also store in memory (google guava hashtable where the token is the key)
the token must be passed along with every api call in the authorization token as #ipa suggested
the server code checks if the token is in its memory cache the user info are already available otherwise (e.g. the api call is done on another node in the cluster) the token is search in the token db
once the token is found you can check expiration, roles, etc...
This grants a good level of performance and security, the token can be generated with any arbitrary algorithm even a relative slow one since you don't have to recalculate it on every api call. Also this works with a stateless service wich can be scaled up horizontally.
I assume you use https and therefore all the traffic is encrypted. I'd suggest one of the following principles.
Basic Authentication
You can add the credentials in the Authorization header of the request. This credentials are encoded with Base64 (see below). This credentials could be sent on every request and then checked with your DB. To get this faster and less IO intensive you can still use a cache. Once I implemented an API like this without a cache and was able to handle thousands of requests per second.
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
Authorization Token
There are different ways to implement your idea with a token. A common one is that every API user has his own token usually called api key which never expires. Another one is that you first have to authorize (Basic Authentication) and then get a token back which expires. This one is then used as api key for a certain time.
Either way you have to decide whether to use a cache or not. I would keep it simple and go for basic authentication and check the db every time. Almost every framework has very good support for this approach because it's simple http. If this causes performance issues (I'd recommend performance tests anyway) try to add the table with your credentials to the JPA cache. If you want to implement something with expiring tokens have a look at Infinispan.
You can store token in Redis. If you are going to store it in DB, make sure you optimise server (if you are managing it) for read operations. I have couple of implementation where folks have used key value store as well. Hashtable is also good idea.