Make jwt token expired after one of the user's property has changed - node.js

is it possible to make jwt token expired after one of the user's property has changed ( for example - activated: false or role: [ADMIN] )? Or maybe there is another way to solve this problem?

Typically a JWT expires only when the expiry date for that token passes. But this doesn't mean that a JWT cannot expire logically for other reasons. One example would be that your Node application receives a request with a valid JWT, but the token belongs to a user whose account was recently deactivated. The workflow might look something like this:
Your Node app receives the JWT
It decrypts the JWT, and extracts the username
Then it queries a user table in your database to check the status of the account
Having discovered that the account is not active, your Node app redirects to the login page with an error message
It is generally up to you to determine how to proceed with a JWT. The JWT just protects the token from being manipulated by the user.

Related

A few questions about json web tokens

I have recently started using json web tokens and I have a few unanswered questions
what would happen if a users token expires while they are online? would they be forced to log in again when they request the next protected route? and if so it feels like there has to be a way around this so that the user does not randomly get logged out
how would you log someone out before the jwts expiration date considering the client holds all the info
any clarification on those 2 questions would be appreciated
what would happen if a users token expires while they are online? would they be forced to log in again when they request the next protected route? and if so it feels like there has to be a way around this so that the user does not randomly get logged out
When you make a request in a webapp, you need to pull in the available token. So the answer is "what does your app do?". There are lots of things you can do, such as making the request with the invalid token, or no token at all. But obviously that's not really a good idea. The best strategy is to:
Before every API call needing a token, check if the current token is valid
If the token isn't valid ask your auth provider to get a new token. This is known as silent authentication. How the provider handles this is totally up to them, usually they have a HttpOnly cookie saved for a secure domain, and return a new JWT.
If the silent auth fails, then the provider will tell you to log the user in.
At this point the best course of action is to redirect to the user to the auth provider using the same "login strategy" they previously used, to get a new "session" and a new "token".
how would you log someone out before the jwts expiration date considering the client holds all the info
Logging out is completely separate from token expiration. Logging out from a user standpoint is:
Tell the auth provider to remove the HttpOnly secure cookie
Delete the JWT in the browser
Change the UI to display the user as no longer logged in.
But that doesn't expire the token. The token will always be valid until the exp date. If you want to also prevent that token being used as if it was valid, you must deny-list the token using your AuthZ IAM as a service. For instance, if you were using Authress to manage access control, a DELETE https://api.authress.io/v1/users/{userId}/tokens/{tokenId} would cause subsequent checks using that token to return Forbidden. However, I will stress, the token is still valid, but you've taken the step to mark it as Deny-listed.
would they be forced to log in again when they request the next protected route?
If there is no other information that associates the session with the logged-in user (for example, there aren't any cookies or other tokens the server can use), yes.
Yeah, it's not very user-friendly, and JWTs often have a short expiry time. A common solution to this issue is to provide a refresh token as well, which could be stored in a HttpOnly cookie:
A refresh token has 2 properties:
It can be used to make an API call (say, /refresh_token) to fetch a new JWT token before the previous JWT expires.
It can be safely persisted across sessions on the client!
This way, the client can always have a valid JWT at any one time; they won't have to log back in, or logout and then log back in.
how would you log someone out before the jwts expiration date considering the client holds all the info
You can implement logic on the server to somehow blacklist or ignore the JWT from a particular user until they log in again. For example, after parsing the JWT, you could check to see whether the server considers the token to still be usable or not. If not, return a 401 error.

jwt token how to ensure the payload is updated when database change

I have a question regarding the concept of JWT token type of authentication.
So suppose I sign a jwt token after user logged in, the token payload contains the username and userRole. I then return the token to the user and store in user's localStorage.
Now, if i change the userrole in database, i.e. from normalUser to AdminUser, how can I then ensure the payload on user's localStorage also change?
I have an issue when if the user is an admin user, when he signs in, a jwt is stored in his localStorage. Afterwards, I set his role to normal user, he can still access the admin features because his localStorage contains the role of AminUser.
Can someone suggests a correct way to implement authorization so that the token is updated on user end?
Thanks.
What is your trigger for changing the user's authorization? If you're saying that you're opening your database client (Say for example MySQL or PostgreSQL) and manually changing the authorization for the user, then there's no way your server or your client to know of that change (As far as I know at least) and they cannot react to that particular change.
If your trigger was some request sent by the user, say logout or change authorization, then you should respond with the new token for that particular request and store it, easy peasy.
If your trigger wasn't related to your client, and it's somehow something happening on your serverside, then you should have a socket opened between your server and your client, and emit that change from your server to your client.
That way you ensure the client is always up-to-date.
But that's still not enough, because yeah you're keeping the client up to date, but what if he saved the token and replaced it after your update? He/She can still access admin features even though you told them they're just normal users. For that you're gonna need to validate every request done by any of your users, and check if they're allowed to make that request in the first place.
You cannot really trust clients. You should find a way to invalidate your jwt tokens. Your client should get a new token when you reject them. You can rotate your tokens using refresh key.
In order to do that:
Keep your token lifetimes short
Or:
Store blacklisted tokens in the database and reject the invalidated tokens.

How should I handle RESTful authentication while using JWT tokens?

I have read many articles and viewed many videos but there are a lot of contradictions. I try to avoid any external libraries and build the system from scratch, I have read about oAuth 2 but it is more confusing.
This is the flow that I think is ok untill now:
User fills a form using email and password and submits it.
Server verifies the password if it matches and responds back with a httponly cookie with a signed jwt token that expires in like 10
minutes. (I know I have to protect it against csrf attacks)
User gets logged in and every new request he is making to the server he will send the cookie in the header automatically and the
server will verify the token.
Everything is fine but I have encountered some issues and have some questions:
I want the user to stay logged in even after opening a new session so there is no need to login after the token expired or when he closes the browser.
What should happen if the access token expired?
There should be a refresh token attached to the user in database that gets added when the user logs in with an expiration of ex 7 days, then the server will respond with a cookie containing that refresh token?
On the new request while access token is expired,the user will send the refresh cookie to the server, if it matches the user database refresh token,server will respond with a separate cookie that will renew the access token?
If there is a refresh token where should you store it and what format? (cookie,database or where?)
Should I keep the user logged in based on this refresh token cookie?If is it httponly I can't read it and set the state that user is logged in. How should I do it?
I heard about that revoking the jwt token is problematic. How would you fix it?
How would you do this whole thing?Please explain the workflow, I try to avoid localstorage,as I read everywhere that is not safe for sensitive data.
I have implemented and deployed to production systems that do exactly the kinds of things that you are asking about here so I think that I am qualified to provide you with some guidance to solve your particular issues and answer your questions. The flow that you have listed above in the numbered list is definitely the correct path so far. I do understand your confusion going forward from there because there are many different options for how to approach this problem.
In addition to providing a login route that returns a new JWT to the client when the user submits a login form to the server, I would recommend also implementing a token refresh route that accepts a still valid JWT that was received from the initial login process and returns a new JWT with an updated expiration time. The logic for this new token refresh route should first verify that the provided JWT is still valid by matching it with a user in the database. Then, it should generate a new token using the same JWT generation logic as the login route logic. Then, the application should overwrite the access token data in the database for the user replacing the old access token with the newly generated access token. It is not necessary to keep an old access token in the database once it is no longer valid, which is why I suggest simply overwriting it with a new one. Once all of that is finished and successful, you can return the new JWT to the client and then the client should now use that new JWT when making any additional authenticated calls to the server to maintain an authenticated interaction with the server. This logic flow would keep the user logged in, because the client would have a valid JWT before calling the refresh logic and it would have a valid JWT after calling the refresh logic. The user should only be recognized as not logged in and not authenticated if they are no longer able to provide a valid access token that is associated with a user in the database.
As far as cookies go, whichever method that you use for maintaining the cookies on your client should be used for setting the refreshed access token as it is for setting the initial access token that you receive on login. If the server finds that an access token is no longer valid at some point in the future, if for example your client is not used after login until some time after the access token has expired, then the client should recognize a server response indicating that this is the case and present the user with the login flow on the client again so that a new access token can be acquired and stored in a cookie on the client.
I would not worry about revoking JWTs and instead just let them expire if they do and initiate a new login flow if it is found that a JWT has expired. Also, instead of using local storage I would suggest using session storage to store your JWT so that you have it for the duration of your user's session on the website and it is removed as soon as the browser has been closed. This will prevent the JWT from persisting beyond the session and should assuage your fears about saving sensitive data in the session storage. Also, when generating your JWT, you should also make a point of not storing any sensitive data in it because JWTs are easily reverse-engineered. This can also prevent any sort of sensitive data from being exposed on the client.
EDIT:
The key thing to remember when developing your server API is that you should have two different classes of endpoints. One set should be unauthenticated and one set should be authenticated.
The authenticated set of endpoints would not require an access token to be included in the request. An example of this class of endpoint would be your login endpoint, which does not require an access token because it actually generates an access token for you to use later on. Any other endpoint that does not expose sensitive or important information could be included in this class of endpoints.
The unauthenticated set of endpoints would require an access token to be included in the request, and if no access token or an invalid access token is detected the endpoint would respond with a 401 HTTP response code (indicating an unauthorized request). An example of this class of endpoint would be an endpoint that allows a user to update their personal information. Obviously, a user cannot update their own information if they cannot provide credentials to prove that they are the user whose information they are attempting to update. If the client receives a response with a 401 response code, that would be the signal that the client would need in order to tell the user to re-login so that a new valid access token can be retrieved. This possibility can be avoided on the client if the client is programmed to periodically check the expiration of the JWT that is currently being held on the client and initiate an access token refresh, but obviously you should still have logic in place to detect and respond to a 401 response code so that the client user flow is managed properly.

Can we use JWT for Session management?

After introducing JWT in my own application. I am facing some issues, might be I do it in wrong way. Please Suggest me the best way of implementation.
Technology Stack : (MERN) MongoDB Expressjs React Node.
After successfully login , I am creating a new JWT token by adding "user-id" in to it and return back to UI layer. At UI end I am storing that token in session storage. This token I am using for all further requests to the server. Before going to the controller I am checking Token in middleware for validtaion by using JWT verify. if successfully verified then next() else return an error with an invalid token.
Issue accurs now :
Register with USER 1
Login with USER 1
After successfully login copy Token from session storage.
Then Logout USER 1
Register with USER 2
Login with USER 2
Paste in session storage Token of USER 1 into USER 2
After refreshing a page USER 1 dashboard again instead of USER 2.
Any help or suggestions for following two points:
How should I manage user Session by JWT?
How should I manage API Authentication by JWT?
You should either not store tokens in the browser session or at least delete it when logging out. The token contains all information about the user as well as the signature, that verifies the validity of the token. If you copy & store it, it is still valid. Logging out the user doesn't invalidate the token.
You should add an expiry to the token to make it valid only a short time, but you need to refresh it then in intervals before it gets invalid. The normal way to do this is to use a refresh token which has a longer interval and keeps the user from logging in again and again.
When the user logs out, you should stop re-issuing access tokens from the refresh token.
See https://jwt.io/introduction/ for further information about JWT.

Password Change Required response from RESTful Token Service

I am trying to determine the best way to enforce password expiration rules in my solution.
The server-side exposes a REST API for operations with a custom active Security Token Service (of sorts). Client applications pass user credentials to a REST endpoint where the user is authenticated on the server. The response includes a custom security token representing the user which is then passed to other API methods so the call can be authorized. The server is stateless and does not maintain any reference to the identity or claims information (i.e. session-less).
We have password expiration rules that are enforced by the server. So, when authenticating a user, it is possible that their password has expired. I need to communicate this to the client so they can do whatever is needed to have the user change their password. (There is another REST endpoint for changing the password on the server.)
Questions
It seems to me that authenticating a user with an expired password should fail. However, I need to know the identity of the user changing the password when making the second API call, so should I go ahead and return a token even when the password has expired?
How should I inform the client that a password change is required? I thought about including this as a claim in the token, but that would require me to reissue a new token after the password has been changed or modify the original token which isn't allowed. My other thought was a custom HTTP Status Code that I would correspond to meaning Password Change Required.
The answer to this question probably depends on the previous two, but I don't want to authorize a user that has an expired password if the token is passed to any other APIs (besides changing the password). What's the best way to handle this?
So, what I ended up doing (certainly not the be-all-end-all solution) is having my Authenticate endpoint return an AuthenticationResultCode enumerated value in the response in lieu of a simple pass/fail boolean. Possible values for the enumeration include:
ValidCredentials - the user was authenticated and the AuthenticationToken is included in the response.
InvalidCredentials - the user was not authenticated
CredentialsExpired - the user was authenticated but their password has expired. I have yet to determine if the AuthToken will be included with this result.
NoCredentials - no credentials were provided to the request
Now the client has more information about the result than a pass/fail value (which I really never checked anyway) and I can take the appropriate action in response such as automatically displaying the ChangePasswordDialog when CredentialsExpired is received.
Like I said, still working out whether or not I should still send the token when the credentials are expired because I don't want to be able to authorize a user if their credentials are expired but they've already been authenticated once and I don't think it makes sense to re-authenticate after changing the password (after all, I have to be authenticated so I can change the password in the first place). Maybe just a simple IsLocked or IsExpired property on the client will suffice...

Resources