How to properly use refresh token on different devices? - jwt

After successful authorization on the client, two tokens are saved in cookies, one of them is access the other is refresh, when the access token expires, the client sends a refresh and the server issues two new tokens to the client, the point is, the fact is that if the user logs in from another device, for example, from a phone , then the refresh token on the first device will already be invalid. Refresh token is stored in the database table users, in the table fields: email, password, refresh_token.
That is, when authorizing on another device, the refresh_token field will be updated and on the first device, the refresh token is already invalid in the cookies. How to make it possible to use the refresh token, not only on one device? I saw that I needed to do something with the device identifier, but did not understand, I also did not understand where to get this device identifier. I would be grateful if you describe in detail how to properly organize this process.

Related

Firebase logout clients when email or password changed

I have a functionality in my app where the users can change their password or update their email address.
According to this document https://firebase.google.com/docs/auth/admin/manage-sessions i would assume that when the same user is logged in on another device at the same time that the refresh token should be revoced when the password changes and the user should be logged out.
It seems that this does not happen in my case. I use these two listeners to detect the changes:
addStateDidChangeListener
addIDTokenDidChangeListener
They are normally working when I login/logout via the Firebase login and logout functions but they don't get called when I change the password on another device.
Is there any way to get notified when a user change the password on another device?
Firebase Authentication uses ID tokens to maintain the authentication state on the client, and these tokens are valid for one hour. Only once the SDK needs to refresh the token (which it automatically does about 5 minutes before the token expires) is it guaranteed to detect the change, so that may take up to an hour.
If you want to force refreshing of the token before it expires, you can call reload on the User object.

Does I understand access and refresh token technique for authentication correctly?

After doing some research in using JWT with Access Token and Refresh Token for authentication. I understand this in this way.
After login, return to user Access Token and Refresh Token (using same technique JWT for both).
Saving Refresh Token in Database (one User can have multiple Refresh Tokens for multiple devices).
Whenever user sends a request with invalid Access Token, check Refresh Token and call another api to get new Access Token (doing this in client side). After that, call api to get data again with new Access Token.
If Refresh Token is invalid, deleting its record in database and user must to login again to get new Refresh Token.
Does I understand Access and Refresh Token technique correctly? Please give me some advices. Thank in advance.
Of the 4 steps you listed, some look more or less correct while others do not. I will begin this answer by giving the premise for why refresh tokens were created and what is their main purpose.
Using the JWT pattern with only access tokens, there is a potential usability problem when the JWT token expires. Consider as an example a banking website. When a user logs in, he receives a JWT token with a certain expiry (typically stored under the exp key in the claims section of the token). If the token is given say a 5 minute expiry, then from a usability point of view, it means that the website would have to force the user to manually login every 5 minutes. Obviously, this is not the best user experience, because it means that a user who happens to be in the middle of some business process when the token expires might lose all that work. This is where refresh tokens step in to alleviate this problem.
Using the JWT pattern with refresh tokens means that the user receives both an access and a refresh token. A typical workflow here might be:
After login, return to user Access Token and Refresh Token (using same technique JWT for both). The receiver notes when the access token is set to expire (say 15 minutes).
As the expiry of the access token approaches (e.g. 10 minutes), the UI will send the refresh token to the backend to obtain a new access token (and refresh token). This could be done explicitly, e.g. on a website which displays a popup asking if the user wants to continue. Or it could be done in stealth mode, with a REST call being made under the hood to get the new access token.
For the edge case where the refresh token cannot be used to obtain a new access token, then the very next user action which requires authentication would fail. In this case, the user would have to redirected to the login page. But, as this case should generally be rare, it does not disqualify the refresh token pattern.
I would also point out that storing the access/refresh tokens in the database largely defeats the purpose of the JWT pattern. One major reason for using JWT is that it pushes the user session state out of the application and onto the user. By storing tokens in your database, you are totally making your user sessions very stateful, which has all sorts of potential drawbacks. Consider using the suggested workflow above to avoid doing this.
The way I see it, your refresh token needs to be stored and associated with the device and the user.
Example:
User Logs In in Device A
Call Login endpoint
Validate user is valid
If valid, generate a refresh token associated with the userid & device
id
store required data to your table or storage engine (user_sessions..etc)
user_id | device_id | refresh_token | expires_at
Return the payload with access_token, refresh_token , access_token_expires_at, refresh_token_expires_at
Front-end, store the payload
when consuming a resource, check the following
If refresh_token_expires_at > now then logs them out , show your session is timeout (or you can have a never expired refresh_token.. ex. refresh_token_expires_at can be 0)
if access_token_expires_at > now then call refresh token endpoint along with your payload.
on the refresh endpoint, validate the call and check the refresh token against the data stored.
if refresh token is valid for this user+device, generate a new access_token
return the access_token and its expires_at
If the refresh token is INvalid , return invalid
front end will log the user out.
** in any case, if a refresh token was compromised, it will be only for that particular device/user. A user can then deactivate or remove the device from their list. This action will invalidate the refresh_token on their next refresh call.

Force Logout of user on multiple devices using JWT

We have an existing REST API that is currently using JWT.
Client came with the requirement that users can only use 1 device at a time. For example, if user logs in from iOS device then logs in Android device, then the iOS device should be "forced" to logout.
Since we are using JWT, we are not keeping track of tokens, except a Token Blacklist when user click Log Out.
I researched on how to "force" log out the user and it seems we would need to keep track of the last token used by the user, then invalidate that once we detect a new log-in.
Is there no cleaner / alternative way to achieve above?
Here are the steps to implement your requirement:
step 1: save the timestamp of last user activity performed for password update or logout from all device
add a column lastSessionResetDate to store last password update date in your user table
While performing forget password/change password apis or at logout-from-all-device, update lastSessionResetDate
step 2: set lastSessionResetDate in JWT Claims, when generating JWT token
example of setting claim while token generation
//make a claims map (`Claim extends Map<String, Object>`)
Map<String, Object> claims = new HashMap<>();
claims.put(CLAIM_KEY_USERNAME, user.getUserName());
claims.put(CLAIM_KEY_AUDIENCE, "web");
claims.put(CLAIM_KEY_CREATED, new Date());
claims.put(CLAIM_KEY_LAST_SESSION_RESET, user.lastSessionResetDate());
//set claims and build JWT
return Jwts.builder().setClaims(claims).setSubject(user.getUserName())
.setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(System.currentTimeMillis() + yourTokenValidity))
.signWith(SignatureAlgorithm.HS512,"yourSecretEncodedBase64")
.compact();
You can get any of claim value at time of parsing JWT token.
Step 3: Time to validate user and session
After getting User entity by JWT, check if lastSessionResetDate is valid till time, else unauthorized the request.
You must be already fetching user from database, so you don't need to make any other query because our new added column lastSessionResetDate will be a part of the same query result. (You just have to add one if-else block).
Note: You can also get prompt value in response from users for log-me-out-from-other-devices
Hope you have got an idea, Happy Coding!!
Assuming you use JWTs as Bearer tokens, depending on your requirements, it might not be sufficient enough "to keep track of the last token used by the user, then invalidate that once we detect a new log-in.".
As Bearer tokens (independent on whether it's JWT or not) are send by the client, the client is also aware of the token, which allows the sender to also copy and paste tokens from one device to another (or issue requests including the same token from various devices).
Your requirements sound like a standard use case for proper session management that allows e.g. for user-agent binding.

Tracking multiple logins from the same user with Stormpath

I'm working on a mobile application that uses Stormpath on the server side for authentication and authorization. I need to support the same user signing in on more than one device, but I want to be able to keep track of it and limit it if I want to.
My application currently uses Stormpath to sign in the user using email/password or MDN/password and upon successful login returns a JWT token to use for API access to the server.
I'm thinking of the following approach:
Keep a list of sessions in the user's account. Every time the user signs in, a new entry is added with the device_id and the JWT provided. When the user signs off, the entry is removed or marked inactive.
When a user tries to sign in on another device, if I want to restrict to only one active device, I would set the other entry to disabled and expire the JWT so the application can detect it and require login again.
If I wanted to restrict the user to a maximum of n sessions, I could just count the entries and force the user to sign off on one of the other sessions before allowing her/him to sign in on the new device
Is this a good approach? Is there a better way to do it? What are the issues with this method?
I work at Stormpath on the mobile SDKs. You can use the access / refresh token feature that we have to accomplish this.
Every time the user signs in, an access and refresh token are created. When the user signs off, the refresh token is deleted, as well as the access token.
When a user tries to sign in on another device, if you want to restrict to only one active device, you can delete all of the other access & refresh tokens.
If you wanted to restrict the user to a maximum of n sessions, I could just count the entries and force the user to delete one of the refresh tokens before allowing her/him to sign in on the new device. You would then go through the access tokens, and delete ones with a matching "rti" (refresh token ID)
Several notes about implementing this:
If you're using a Stormpath Framework integration, the default is to verify an access token locally (instead of sending it to Stormpath to validate). This is because they have a signature that can be validated by the SDK. However, to log out a user, you'll either have to set this to remote validation, or use a short access token life (and use the refresh tokens to control each "session")
Refresh tokens can't store "customData", so you'll have to maintain metadata about the refresh token in either the account's customData, or in your own database.
Alternatively, you could "create" API Keys for each user, and use that instead of sessions for each user. You can use the API Key name or description attributes to keep track of where the user signed in from / etc.

Stateless Token Auth security

I'm new to ReST and am implementing a ReSTful token authentication, trying to use Django-Rest-Framework JWT, in a mobile web app in the standard way
client sends credentials
server verifies and sends token and expiration date back. Deletes token from db
client calls refresh token when user makes request and token is about to expire
on client request, server verifies token signature
on expired token mobile app logs user out. Mobile app checks expiration not server
I decided to make the mobile app check the expiration date since I read that is ReSTFul, and the server checking it requires it to store tokens which is not ReSTful
I have a few security questions regarding the above implementation:
1) Doesn't obtaining one token give the attacker complete access to the user's login no matter how many token refreshes happen?
Even if it's over https, let's say by some means a token was retrieved by an attacker, i.e. ssl interceptor proxy.Obviously the mobile application won't allow them to login, but they can grab data by calling the api with the token through any HTTP client.
2) What is the purpose of having refreshing tokens in the first place if the server considers all of them as valid?
There seems to be no forward security in this.However, if the server stored the tokens and kept their expiration dates, a complete user compromise would be stopped, but not a per session compromise. Obviously with an SSL interceptor they could still compromise the user, but would need to catch every login. However that implementation is not ReSTful.
First of all, expired tokens are valid tokens, but you can check if token expired or not, before taken any action, and reject the ones expired. There are several things you can do to increase the security of your app:
You can add the hashed password inside token. Therefore if user lost his/her mobile, when password changed in another device, you can reject the tokens with old password hash.
This one is not totally restful, but not that bad as well: you can add a table called revokedTokens in db which keeps track of id of tokens (obviously you should add it to token) user revoked, if you receive request with that token later on, you can reject it until it expires. when it expires you can remove from the table, as expired tokens won't be a problem anyway.
You can add the device's host name when user logs in to the token, and compare it with the request's host name, to have additional layer of security for ssl interceptor attack. Yes, it's not total protection, but still a bit better, as attacker needs to change his/her host name in addition to sending the token from another device.
Hope this helps.