I have implemented JWT based security in a test Core Web API REST project, it is working fine but I am not sure that I see the benefit of this. The web says JWT is good because it's lightweight and can be used to verify that the source of data but in my implementation:
The client first provides a username and password to authenticate
If user + pwd is ok the a token is returned and every subsequent call to the api uses that jwt token (instead of the username and password) to authenticate.
This is fine but why not just use the username + password on every call to the api (and skip the complication of managing the token)?
In fact in my case there's additional complications because I now have to factor in an expiry date (of the token) that resides outside of my system.
Can someone explain what I'm missing here?
One of the main benefits and motivations for using JWT is that it allows your server side application to push all session state information outside of the application. That is, in a theoretical limit, a JWT implementation is actually stateless.
To directly answer your question, we can compare the workflows for what happens when username/password is submitted in every request versus submitting a JWT.
First, a JWT contains a claims section, which is typically written by the issuer of the token, i.e. the server side application. One of the fields is called exp, and contains the expiry time of the token. One property of JWT is that it is not possible for the user to tamper with them. This is enforced via a checksum, which would change if any part of the JWT changes. Taken together, this means that the user cannot alter the expiry time (or any other claim), and the server can implicitly trust this time. When the user submits a request with a JWT, in theory all the server has to do is just check exp to see if the token still be valid. That is, the session state actually lives outside the application, at least in theory.
In contrast, when the user submits a username/password each time, the server has no way of knowing what to do just based on that information. Rather, the server has to maintain the session state itself, and this can be costly both in terms of memory and performance.
In practice, JWT is never completely stateless, but, using a good implementation, it is usually possible to get the memory footprint very small, requiring only a bit of space in a cache (e.g. Redis or a similar tool).
JWT tokens seem like a very good idea. You can send a request to some API without using your username/password secret pair.
Still, I don't fully understand the benefits that it gives. I have two questions:
To get the token, user still needs to send his credentials to some server that issues these tokens. Isn't it a weak point of all this?
If attacker steals the token while it's being transferred, he can use it to pretend he is someone else. The only difference between this and using user/password combination is that JWT tokens get expired after some period of time, so attacker doesn't have much time to do his thing.
Is my understanding correct? What am I missing?
Yes, it does have to exchange the pair once, but this is still minimised risk compared to doing it every time you have to make an API call.
There are many ways tokens can be stolen, and the common way to detect this is by checking for sudden unexpected changes in IP addresses. This method is not robust and is easily spoofed. However, if we're able to detect the theft, then it's a simple matter of blacklisting the token. Hence, the entire strategy is dependent on detecting that the theft has occurred. For this reason, you should use the concept of rotating tokens: See more in this blog for how this would work as it's too long to explain in a SO answer.
I have used JWT before, but they were API that didn't need logout feature.
I need to implement logout feature for a API of an android app and SPA. When I looked it up I found that there are two ways to do it.
the easiest way is to delete the JWT Token from client side and call it a day.
The logic behind this is that since no session of any kind is maintained in server deleting the token in client side should be enough.
But it still leaves the possibility that, if the token falls in wrong hands they can still use it even after the user is no longer using the token.
Given if the app is well designed and uses HTTPS then chances of this happening is very low and can be minimized by keeping the valid time for the token short. But in my case the tokens are valid for 30 days.
the second option is to maintain a blacklist of tokens in server side
This solves the problem of the token still being usable even after user has logged out and stopped using it.
But it adds a complication of needing to run a cronjob to remove expired token form the blacklist table. Otherwise the table will eventually become ridiculously large.
It also kinda defeats the point of using JWT. Maintaining blacklist is very similar to maintaining session. We have to run an additional db query for every request. And it scales badly, as the no. of users grows the no. of token that needs to be blacklisted will also grow (this will be a bigger problem for API like mine with multiple front end apps and long validity period for the tokens).
Then I got an idea for third way.
Add jwt_secret row in user table that stores randomly generated string. Use it to sign the JWT Token then on every request use user id in the jwt payload to get the user form db(which is not an extra query, we have to do this anyway) and validate the token signature using jwt_secret of the user. When the user logs out we change the jwt_secret which makes all token out there useless.
At first I thought this was a great solution only to realize that in this setup if user logs out of one device or browser he/she gets logged out of all devices.
So is there a another option? Or a way to modify any of above approach to solve the problem. Or am I over thinking this and one of the above option should be used?
For logging out, which as you pointed out is a user initiated action, I don't think you need to do anything extra. If the user somehow did not delete his JWT, then so be it. He wouldn't be getting any extra access over to what he is already entitled.
However, your question seems to hint on the problem of how to know that a JWT is valid. Again, as you pointed out, if a JWT somehow fell into the wrong hands, then there may be no avoiding this. But, with each request you would typically be doing several types of validation against that JWT, e.g.
checking the claims of the JWT, such as the token expiry date
assuming the claims pass, then checking that user's ID against your database table to make sure the account is active, has not been suspended, etc.
My point here is that if you need to keep track on the server side that a logout has happened, you might need to persist this to a database. But, I don't think you would need this.
I've been reading a lot about JSON web tokens lately. A big thing that I see is that to have a timeout based on last access, and not a hard timeout, you need to use a separate refresh token. The one thing I don't see is WHY.
Why would a separate token be needed? Why not just refresh a last access value in the initial token every time it's received? The initial access time can still be preserved and a longer hard timeout established regardless.
There are so many options on how to implement JWT and most of what it comes down to is your requirements and how you want the application to behave.
My guess is that reissuing the token every time and updating on the front end will not perform well in a large application. You have to replace the token completely because the last access time stamp is part of the payload and thus, if you change any part of the payload, the signature for the payload will be different. If it's not part of the token, it accessible on the front end and could easily be changed to allow indefinite access.
Refresh tokens are typically associated with OAuth2. Setting up an Authorization server to issue tokens provides a nice division of responsibility and abstracts out a fairly large portion of your application in well documented, standard based way. It also allows you to revoke the refresh token, making it possible to revoke access (although not immediately) of your users. Most importantly it allows you to use the same access token for each request without reissuing it.
Considering that, by definition, a REST API is stateless: is the "logout" operation useless?
I mean, I'm creating a REST API using encrypted JWT. Each token has an expiration time of, let's say, 60 minutes. If I save on a database table the last tokens generated by the API, the "logout" would be done deleting them from the table of valid tokens. But, if I do that, I understand that the API will cease to be stateless, right?
So, I understand that I shouldn't do that. The only solution that I'm thinking is make the JWT expiration time shorter, to 5 minutes, don't implement a "logout" operation and just let the tokens expire.
Is this the correct approach?
I mean, I'm creating a REST API using encrypted JWT
The JSON Web Token (JWT) tokens encodes all the data about the grant into the token itself. The most important advantage of this approach is that you do not need a backend store for token storage at all. One disadvantage is that you can't easily revoke an access token, so they normally are granted with short expiry and the revocation is handled at the refresh token. Another disadvantage is that the tokens can get quite large if you are storing a lot of user credential information in them. So if:
If I save on a database table the last tokens generated by the API,
the "logout" would be done deleting them from the table of valid
tokens
Then you would lose the most important advantage of using JWT and also, still have all those disadvantages, which seems unreasonable to me.
So, I understand that I shouldn't do that. The only solution that I'm
thinking is make the JWT expiration time shorter, to 5 minutes, don't
implement a "logout" operation and just let the tokens expire.
Is this the correct approach?
In my opinion, if you're planning to use JWT, YES! it's better to rely on the token expiration. For more details on this approach you can check this question out.
Is “logout” useless on a REST API?
Regardless of the fact that you're using JWT and similar to any other decent questions on computer science, the answer would be It Depends. The most important advantage of Statelessness is that your API would be more scalable. If you choose this path, probably, every request on your API should be authenticated, since you may need to search a backend store for the given token or decode a JWT token. So, in this case you may have some performance cost on a single node but in a big picture, you would still have the scalability. I guess what i'm trying to say is, if you do not need that scalability, you're better off to choose a Stateful approach. Otherwise, pure REST principles is the way to go.
Automatic token expiry is a separate concern from an explicit "log out" mechanism and, as such, they are both perfectly valid actions regardless of whether your API is ReSTful or not.
When a user logs out they are making a conscious decision to invalidate their access token - for example, if they're using a public computer or borrowing someone else's device temporarily.
Automated expiry is used to ensure that the user must revalidate, in some fashion, on a regular basis. This is good for server-side security.
Access tokens are not about sharing session state between client and server - it's entirely possible to implement an access token system without shared state and the token itself doesn't implement session state, it's only used to verify that the user is who they claim to be. As such, access tokens are not really anything to do with the statefulness of the API.
I think it depends on the behavior that you want for your application, and how secure you need it to be. Do you really need to invalidate the token?
For instance, you could just remove your token from your frontend (browser or app). In theory, it is the only place that stores that particular token. If the token is compromised, it will still be valid until it expires, though.
If you really need to invalidate it server side, a common approach would be to create a blacklist with the token, and clear the expired entries from time to time.
But what if you need your application to accept just one token for each user, like in a bank app that you can only be logged in one device at time? For that purpose the blacklist won't do the job, so you will need to store a single token for each user and check if the passed token is the same. At logout, you would just clear that unique entry. Or you may just use sessions.
So, it is not useless, It just depends on your application.
I would argue that your API is already stateful just by the sheer fact that you have a token around. I also wouldn't get too hung up on REST purity, meaning that everything has to be stateless come hell or high water.
Put simply, if your application requires login, then you need a way to logout. You can't implement a short expiry because that's just going to be a really annoying experience to consumers of the API. And you can't just have no logout at all, because thats a potential security flaw.
I have a similar REST API that I support and I implemented a logout endpoint that is a DELETE call. It simply deletes the token information on the server side and clears any type of authentication for the logged in user.
TL;DR
No, a logout is not useless in a REST API. In fact, for APIs that require authentication, it is more or less a necessity.
With a short expiration time on the token I would think for most applications deleting the token from the client on logout would be a good solution. Anything more would rely on the server and no longer be stateless.
The good solution here would be to delete the token from the user.
So typically when you log in, you will get back a token from the server and store it in localStorage or sessionStorage (depending on the user wanting to be logged in after closing the tab) in the browser, and then send the token from there in the headers with any request that you make to your api.
Then if the user logs out, you don't even contact the api (you don't make any requests to your server), you just clear the sessionStorage or localStorage, use the command localStorage.clear() or sessionStorage.clear() , and then if the user will want to send more requests, he'll have to login again in order to get another token.
One drawback to this approach is, that if a virus, for example gets the token from the local or session Storage before the user logs out then, it will still be able to send requests as you, as the token will still be valid.
One solution to that would be to create a token blacklist in the database, and store the token there if the user logs out, until the token expiration time. However, every time the user would request something, the database would have to be consulted to check if his token is blacklisted, lengthening the process, and making your API stateful.
You can generate a new token that it already expired i.e. expiration is 1sec. and pass it to the user. Any upcoming request will be invalid. This is not optimal solution though..