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.
Related
I am creating a Node js / Express js based, login registration system using JWT (i am using JSONWEBTOKEN npm library).
Whenever a user login, that user gets a pair of access and refresh token. Now for accessing resources user need to send access token to backend.
Now when i verify the access token send by user to backend and if it will not get verified then it produces three types of error (as mentioned is JSONWEBTOKEN library in npm):
Token Expired Error: If i get this error, then in that case i will send response to frontend to send the request to refresh token route to get a new pair of access and refresh token.
JsonWebTokenError: If i get this error then it means that access token is malformed. Then in this case what should i do? Should i logout a user or should i will send a response to frontend to send request to refresh token route to get a new pair of access and refresh token. <-- This is the main question should i logout a user?
NotBeforeError: Since i am not using nbf claim and then in that case i dont need to worry about it.
Please provide your useful suggestion. while building backend security plays an important role.
This is useful to read: JWT refresh token flow.
Talking short, you should logout user if refresh token malformed or expired.
According to JWT idea, access token is short-life token. When it doesn't pass validation due to malformed or expired you have to send refresh token to server to get new pair. User continues to work using new access token without interruption.
If JWT is malformed then just block that call by responding with 403. that's fine. The application then takes the decision on it to refresh the token or not.
When a user logs out please revoke the issued token even if it is a JWT.
JWT also needs to be revoked as best practice. Yes, JWTs are self tokens and expirations already part of themselves. But if user logs out and still their JWTs are not expired means someone can use that token to call different APIs. So it is a security breach.
To avoid such things we should maintain JTI claim of that JWT in our backend with the same TTL with the value of JWT "exp". When the user logs out we have to clear those JTIs and notifcy the API callers about this just putting into some event service from their API Gateways should get to be notified and clear their side cached tokens if anything and cross check with identity system (Introspection).
This is we have to design the system to avoid further security related issues.
First thing is that user will be logged out from front end side.
front end will send request to your node server and token will be verified. Server will only send the response that token is expired or malformed and based on that front end will perform the action.
If token is expired then request for new token.
Is token is malformed then based on your requirements you can show results to your end user. You can either logout user or you can show unauthorized page too.
Suppose, you have role based website and some unauthorized user is trying to access root level routes then you can show unauthorized page.
I have a react app with a node/express back end. I am currently using JWT to make calls to protected routes on the back end. This all works fine. But I want to keep the user logged in for more than just 30 min or so.
What is the best way to handle securing sessions or refreshing an access token when it expires on a client side application?
My Solutions:
-One:
Create a refresh and an access token. Have the access token be short lived. And sign the refresh token with a unique id given to the user in the database. Then check verify the token with this id. Then when the access token expires send a 401 back and then get the refresh token from local storage to create new tokens and then try the call again.
Problem with this: there is a lot of back and forth going on and it seems slow.
-Two
Send both the refresh token and the access token on each call and if the access token is expired use the refresh token to create new tokens then proceed.
Problem with this: I don't see why I would then need to send 2 tokens I could just send one and get the job done with that. But then if one or both tokens become compromised they could regenerate forever.
-Three
Send the access token expiration to the front end and if the token is expired send the refresh token and verify it with the unique identifier in the database. Then generate new tokens and continue.
Problem with this: Not sure how secure this would be. But for now this seems like the best solution.
So I am wondering what is the best way to handle refreshing an access token when it expires so the user can keep using the platform?
I'm saying this from experience not a source but the whole idea of JWT s that it's sessionless. there's another solution for handling sessions.
With jwt, you don't need to save it in your database as you sign that JWT with a secret key and you can just verify that JWT has been issued using your secret key. and you can issue that JWT to be valid for more than 30 minutes. It's totally fine. I myself have set it to 180 days. and because it's so long, a user will log in again in this time so you don't have to worry about expiration. but if you want to handle that too, you can parse it in your front end and check it's expiration timestamp and get another JWT before it expires.
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.
I want to enforce a single user session feature for my Angular app because my customers share a single account with their coworkers.
The issue currently, with my implementation. is revoking a valid token stored a client's local storage, particularly a valid Refresh token.
The scenario is:
User 1 logs in with valid username and password, the bearer token will expire in an hour, the refresh token will expire in two weeks
User 2, uses the same username and password two hours later. User 2 is prompted that they are logged in on another device and asked the question of they would like to expire that session and start a new session.
User 2 says yes and the now User 1's session in invalid.
The problem is that User 1 still has a valid Refresh token.
I have no way revoke this refresh token. My Auth API will accept is valid and I will not know whether it is User 1 or User 2's refresh token.
Do I need to start storing refresh token values in my database to resolve this issue? I also thought I could use a different JwtAuthKeyBase64 for User1 and User2, as a way to invalidate User1's token but this doesn't seem like a good way to be using the ServiceStack JwtAuthProvider.
The JWT RefreshToken is used to contact the Auth Server to fetch a new JWT Bearer Token. It will only return a BearerToken if the User still has Access so you can lock the User Account by populating UserAuth.LockedDate which will prevent the user from retrieving a new JWT Bearer Token.
If you want more custom validation you can implement IUserSessionSource and throw an Exception in GetUserSession() to return an Error Response instead of the JWT Bearer Token.
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.