How to handle expired auth tokens in Xamarin MobileServiceClient? - authentication

I am using client-flow authentication in Xamarin.Forms and am trying to figure out how to handle when an authentication token expires.
My Code:
Upon initial login, the user logs in with the native Facebook SDK and I pass the access_token to MobileServiceClient to get back an authenticated user.
var user = await client.LoginAsync(MobileServiceAuthenticationProvider.Facebook, token).ConfigureAwait(false);
I then save the user's UserId and MobileServiceAuthenticationToken in local settings (using the Xam.Plugins.Settings plugin).
The next time the user opens the app, I set the user from settings and skip manual login:
if (!string.IsNullOrWhiteSpace(Settings.AuthToken) && !string.IsNullOrWhiteSpace(Settings.UserId))
{
client.CurrentUser = new MobileServiceUser(Settings.UserId);
client.CurrentUser.MobileServiceAuthenticationToken = Settings.AuthToken;
}
My Question:
This works great. However, I know that the MobileServiceAuthenticationToken has an expiration on it. What will happen in my app when the expiration date is reached? How do I refresh the token without requiring the user to re-log-in to Facebook? I have tried the MobileServiceClient's RefreshUserAsync() method, but I get the following exception:
Microsoft.WindowsAzure.MobileServices.MobileServiceInvalidOperationException: Refresh failed with a 400 Bad Request error. The identity provider does not support refresh, or the user is not logged in with sufficient permission.
Is there a way to test this? (since the token expiration is 3 months from now.) Thanks for the help!

Microsoft.WindowsAzure.MobileServices.MobileServiceInvalidOperationException: Refresh failed with a 400 Bad Request error. The identity provider does not support refresh, or the user is not logged in with sufficient permission.
Since you are using client-flow authentication, you could not use RefreshUserAsync() for refreshing the MobileServiceAuthenticationToken. Your mobile backend does not cache the related access_token and refresh_token for renewing the authentication Token.
Is there a way to test this? (since the token expiration is 3 months from now.) Thanks for the help!
AFAIK, the MobileServiceAuthenticationToken expiration is one hour by default, you could use https://jwt.io/ to decode your token and check the exp property, then use https://www.epochconverter.com/ to convert your timestamp to human date.
For your requirement, you could follow adrian hall's blog about Caching Tokens and refer to the IsTokenExpired method for decode your authenticationToken and check the exp, then manually renew the authenticationToken.
Per my understanding, there are two approaches for you to achieve your purpose:
You need to cache the facebook access_token in your mobile client side, after you manually checked the authenticationToken and found that it expired, then you could manually execute the following code for renewing the token and explicitly update your local cache.
var user = await client.LoginAsync(MobileServiceAuthenticationProvider.Facebook, token).ConfigureAwait(false);
Note: Your facebook access_token has the Expiration Date, so if your access_token expired, then you need to force the user to log into Facebook again before acquiring the new authenticationToken.
Or you could build your custom endpoint for refreshing the authenticationToken and explicitly set a long lifetime for your new authenticationToken, details you could follow this similar issue. Note: For your client-side expiration processing, you need to renew the token before your local authenticationToken is about to expire.

Related

best practices for refreshing access tokens automatically

I'm building a react native app which uses the spotify web api. I'm using the authorization code flow to authorize a user. First I get a authorization code which can be used to obtain an access token and a refresh token. Everything works!
The problem is: an access token is only valid for a limited amount of time. That's where the refresh token comes in. I understand this concept, but I'm breaking my head about how to implement this.
Let's say a users opens the app, requests an access token and uses this for some time. Then, the user closes the app. After 15 minutes, the users opens the app again. The access token has now expired, so I need to request a new access token.
I've come op with several "solutions". Can someone point me to the correct solution?
Solution 1:
Every time the user opens the app, I request a new access token and use this. Problem: when the user uses the app longer than the valid time of the access token, I won't work anymore.
Solution 2:
I use the access token that's stored in the secure storage on every request. When a request comes back with 'access token invalid' (I don't know the exact error code but you guys know what I mean), I request a new access token with the stored refresh token, and then I send the previous command again (with the new access token). But my question here is: can I use some kind of "wrapper function" which checks the response of the request, and if the response is "access token invalid", it automatically requests a new access token and runs the previous request again.
I think certainly correct solution is solution 2,and i think its clear enough.
and for using solution 2 you need somthing like wrapper function,yes its intelligently.
so you should use interceptor:
what is interceptor ?
You can intercept requests or responses before they are handled by then or catch.
in link below there is a good example of implementing refresh token in axios interceptor:
https://gist.github.com/Godofbrowser/bf118322301af3fc334437c683887c5f
I agree that Solution 2 is the best, each time you do a request you can check to see if the Access Token has expired, and if it has then you can request a new Access Token using the Refresh Token as you mentioned and then make your request, in my own project I do this in a FormatRequestHeadersAsync method which calls a CheckAndRenewTokenAsync method where I perform the following check, here shown in C#:
if(AccessToken?.Refresh != null && (AccessToken.Expiration < DateTime.UtcNow))
{
AccessToken = await GetRefreshTokenAsync(
AccessToken.Refresh,
AccessToken.TokenType,
cancellationToken);
}
You can store the Access Token and the Refresh Token and then use something similar to this before you make each request to the API this will refresh your token and then you can store the new Access Token and the existing Refresh Token.

JWT token refresh (sliding sessions) and signout

I am very new to JWT and I ended up inheriting a codebase which makes use of JWT. Now there are some very fundamental problems which I am facing and I am not finding any answers. This question is not code based so please bear with me.
Let us say that my JWT token is valid for 4 hours. Here are my requirements/constraints
If a user is working at 3 hours 59 minutes. their session should get extended by 2 hours and they should not be required to re-enter credentials.
The client side java script must not cache the user credentials in any way.
It is OK to refresh the JWT token with a new one... but you must not do it on every request you make on the server. So the client has to be intelligent to refresh the JWT token when the time is right. You must not try to issue a new token on each and every request you make to the app, because we will end up in a scenario where we have 1000s of active tokens generated within the course of a session and all of them are active. this makes the signout requirement even harder.
Once a user clicks signout. the JWT token should not be usable anymore. Even though its life time is still valid.
If a signout occurs. All tokens which were issued (as part of session extension) should get invalidated. Not just the last one.
I am starting to read about JWT but it seems like my requirements cannot be met with JWT. these requirements are very easy to meet with the session id approach. but I don't want to give up on JWT just yet.
JWT life extension
You can issue a JWT with the old one. Your client app have to request a new JWT when it is close to expiration time. Client knows the expiration time reading the exp claim and can invoke a refresh service to get a new token. If the client app is closed then the JWT will expire and it will be necessary for the user to present the credentials again
Logout
It is recommended to let tokens expire, but you can use a blacklist to store JWT that are still valid but can not be used for authentication:
When user clicks logout
After refreshing a ticket close to expiration time
You will need to add to JWT an unique identifier jti. The blacklist will contain jti and exp. Once current time > exp the entry can be discarded.
See Invalidating client side JWT session

Time expiration issue in JWT

As you know, there are some good reasons for using token based authentication instead of session based.
In session based, of course there is a expiration time. So if user is not active for a while, his session get expired. But before expiring, if he send request to server, his time will be extended.
There is an awesome tutorial here about JWT. I have a question about expiration time for token. Imagine we set the expiration time to 100 seconds, then we sign the token. It doesn't matter user is active or not. After 100 seconds that token will not be valid anymore. This bothers the user. Is there any way to extend the time?
Is it a true approach, or maybe I have a mistake. Any idea?
If I understand the question correctly, it is fairly simple to alter the expiration of a JWT token during creation...
The "exp" (expiration time) claim identifies the expiration time on
or after which the JWT MUST NOT be accepted for processing. The
processing of the "exp" claim requires that the current date/time
MUST be before the expiration date/time listed in the "exp" claim.
More information can be found here https://www.rfc-editor.org/rfc/rfc7519#section-4.1.4
Basically the exp key takes a unix timestamp - set the timestamp to > 100 seconds from now and you will accomplish your goal.
To "refresh" the token your API needs a service that receives a valid, JWT and returns the same signed JWT with the updated expiration.
Silent refresh
There are 2 major problems that users of our JWT based app will still face:
Given our short expiry times on the JWTs, the user will be logged out every 15 minutes. This would be a fairly terrible experience. Ideally, we'd probably want our user to be logged in for a long time.
If a user closes their app and opens it again, they'll need to login again. Their session is not persisted because we're not saving the JWT token on the client anywhere.
To solve this problem, most JWT providers, provide a refresh token. 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!
Here a brilliant exhibition in HASURA BLOG--> https://hasura.io/blog/best-practices-of-using-jwt-with-graphql/
You didn't give further information, but I'll assume you are going to use JWT for web-browser authentication.
you can save your JWT in a cookie with httpOnly and secure attribute and set cookie expiration time long enough(maybe 1 years) and inside of your JWT claims set exp property to a shorter time ( maybe 1 week or something else). now in every request the cookie will be sent to the server so you can check for expiration time.
something like this :
if(decodedJwt.exp < Date.now()){
//token is valid, do your stuff
}else {
//token expired, regenerate it and set it to the cookie
//also update the expire time of the cookie
}

Authentication on Instagram to get the access_token using the API

I'm using the Instagram API and want to get the access_token in order to throw api requests over my own account. When I try to follow the first step and get the authorization code programmatically using RestTemplate I can't get it work.
String AUTHORIZE_URL = "https://api.instagram.com/oauth/authorize/?client_id=<CLIENT_ID>&redirect_uri=<REDIRECT_URI>&response_type=code";
String url = String.format(AUTHORIZE_URL, clientId, redirectUri);
String o = restTemplate.getForObject(url, String.class);
The response is the html code of the login page because Instagram requires the user to be logged in to check if the app is authorized (of course it is, since the app an the user belongs to my own account).
How can I authenticate before throwing that request so they return the code to my redirectUri and not complain about login?
Note: I tried simulating the request to their login form but it returned a 403 Forbidden.
NOTE: I already got a valid access_token, manually generated, and it works perfectly but I want to implement also a process to re-generate a new access_token automatically since they may invalidate it at any time in the future.
Even though our access tokens do not specify an expiration time, your app should handle the case that either the user revokes access, or Instagram expires the token after some period of time. If the token is no longer valid, API responses will contain an “error_type=OAuthAccessTokenError”. In this case you will need to re-authenticate the user to obtain a new valid token.
In other words: do not assume your access_token is valid forever.
Instagram is upgrading their APIs and the flows. Earlier we needed access token to bypass forced login screen. Since yesterday, they have removed that.
Now if you call this code, it will check if you are already logged in or not. If so, it will call the AUTHORIZE_URL of yours and will send a response code. The format will be either:
On success validation - http://your-redirect-uri?code=CODE
On error - http://your-redirect-uri?error=access_denied&error_reason=user_denied&error_description=The+user+denied+your+request
Now what I'm doing is I'm directly calling the above URL of yours every time. Now if the user is logged in, a response code will be sent to you, else user will be asked to login and validate your app and then the code will be sent. Technically, you are eliminating the possibility of the error case! So no need of overhead of storing access token in your database or verifying its validity.
Just try and check now what happens.
PS: If you want to check API behavior, simply type the URL on the browser and check what it returns! It helped me a lot while coding and debugging! :)

Is a Refresh Token really necessary when using JWT token authentication?

I'm referencing another SO post that discusses using refresh tokens with JWT.
JWT (JSON Web Token) automatic prolongation of expiration
I have an application with a very common architecture where my clients (web and mobile) talk to a REST API which then talks to a service layer and data layer.
I understand JWT token authentication, but I am a little confused at how I should use refresh tokens.
I want my JWT authentication to have the following properties:
JWT Token has an expiration of 2 hours.
The token is refreshed every hour by the client.
If the user token is not refreshed (user is inactive and the app is not open) and expires, they will need to log in whenever they want to resume.
I see a lot of people claiming to make this a better experience using the concept of a refresh token, however, I don't see the benefit of this. It seems like an added complexity having to manage it.
My questions are the following:
If I WERE to use a refresh token, wouldn't it still be beneficial to have a long term expiration for good practice on that token as well?
If I WERE to use a refresh token, would that token be persisted with the userId and/or JWT token?
When I update my token every 1 hour, how does this work? Will I want to create an endpoint that takes in my JWT token or my refresh token? Will this update the expiration date of my original JWT token, or create a new token?
Is there the need for a refresh token given these details? It seems that If the user is just using a JWT token to grab a new token (per the link above) then the refresh token is obsolete.
Let me come to your questions a little later down the line and start by actually discussing the whole purpose of a refresh token.
So the situation is:
The user opens the app and provides his login credentials. Now, most probably the app is interacting with a REST backend service. REST is stateless, there isn't a way to authorize access to the APIs. Hence, so far in the discussion, there is no way to check if an authorized user is accessing the APIs or is just some random requests coming through.
Now to be able to solve this problem, we need a way to know that the requests are coming from an authorized user. So, what we did was to introduce something called an access token. So now once the user is authenticated successfully, he is issued an access token. This token is supposed to be a long and highly random token (to ensure that it can not be guessed). This is where the JWT comes into the picture. Now you may/may not want to store any user-specific details in a JWT token. Ideally, you would want to just store very simple, extremely non-sensitive details in the JWT. The manipulation of the JWT hash to retrieve other user's details (IDOR etc.) is taken care of by JWT (the library being used) itself.
So, for now, our problem with authorized access is solved.
Now we talk of an attack scenario. Let's say using all of the above user Alice, using the app, has the authorized access token and now her app can make requests to all the APIs and retrieve the data as per her authorization.
Assume that SOMEHOW Alice loses the Access Token or put another way, an adversary, Bob, gets access to Alice's access token. Now Bob, despite being unauthorized, can make requests to all the APIs that Alice was authorized to.
SOMETHING WE IDEALLY DON'T WANT.
Now the solution to this problem is :
Either detect that there is something of this sort happening.
Reduce the attack window itself.
Using just the access token alone, it is hard to achieve condition 1 above, because be it Alice or Bob, it's the same authorized token being used and hence requests form the two users are not distinguishable.
So we try achieving 2 above and hence we add an expiration to the validity of the access token, say the access token is valid for 't' (short-lived) time.
How does it help? Well, even if Bob has the access token, he can use it only while it is valid. As soon as it expires, he will have to retrieve it again. Now, of course, you could say that he can get it the same way he got it the first time. But then again there's nothing like 100% security!
The above approach still has a problem and in some cases an unacceptable one. When the access token expires, it would require the user to enter his login credentials and obtain an authorized access token again, which at least in case of mobile apps, is a bad (not acceptable) user experience.
Solution: This is where the refresh token comes in. It is again a random unpredictable token that is also issued to the app along with the access token in the first place. This refresh token is a very long-lived special token, which makes sure that as soon as the access token expires, it requests the server for a new access token, thus removing the need for the user to re-enter his login credentials to retrieve a new authorized access token, once an existing one has expired.
Now you may ask, Bob can have access to the refresh token as well, similar to the way he compromised the access token. YES. He can. However, now it becomes easy to identify such an incidence, which was not possible in the case of an access token alone, and take the necessary action to reduce the damage done.
How?
For every authenticated user (in case of a mobile app, generally), a one to one mapped refresh token and access token pair is issued to the app. So at any given point in time, for a single authenticated user, there will be only one access token corresponding to a refresh token. Now assume that if Bob has compromised the refresh token, he would be using it to generate an access token (because access token is the only thing which is authorized to access resources through the APIs). As soon as Bob (attacker) requests with the newly generated access token because Alice's (genuine user) access token is still valid, the server would see this as an anomaly, because for a single refresh token there can be only one authorized access token at a time. Identifying the anomaly, the server would destroy the refresh token in question and along with it all, it's associated access tokens will also get invalidated. Thus preventing any further access, genuine or malicious, to any authorization requiring resources.
The user, Alice, would be required to once again authenticate with her credentials and fetch a valid pair of a refresh and access tokens.
Of course, you could still argue that Bob could once again get access to both refresh and access tokens and repeat the entire story above, potentially leading to a DoS on Alice, the actual genuine customer, but then again there is nothing like 100% security.
Also as a good practice, the refresh token should have an expiry, although a pretty long one.
I believe for this scenario you could work with the access token alone, making
life easier for your clients but keeping the security benefits of a refresh token.
This is how it would work:
When your user logs in with credentials (username/password) you return a
short-lived JWT. You also create a db record where you store:
JWT id
user id
IP address
user agent
a valid flag (defaults to TRUE)
createdAt
updatedAt
Your client submits the JWT in every request. As long as the JWT hasn't expired,
it has access to the resources. If the JWT expired, you refresh it
behind the scenes and return both the resource and an additional X-JWT header
with the new JWT.
When the client receives a response with an X-JWT header, it discards the
old JWT and uses the new one for future requests.
How refreshing the JWT works on the server
Look for the matching db record using the JWT id.
Check if the valid flag is still true, otherwise reject.
Optionally, you can compare the request IP address and user agent against
the stored IP address and user agent, and decide to reject if something looks
fishy.
Optionally, you can check the db record's createdAt or updatedAt fields, and
decide not to refresh if too much time has passed.
Update the updatedAt field in the db record.
Return the new JWT (which is basically a copy of the expired JWT, but with an extended expiration time).
This design would also give you the option to revoke all tokens for a user (for
example, if the user loses his phone or updates his password).
Benefits:
Your client never has to check expiration times or make refresh token
requests, all it does is check for an X-JWT header on responses.
You can add custom refresh logic based on IP address, user agent, max-token
age, or a combination of those.
You can revoke some or all tokens for a user.
If I WERE to use a refresh token, wouldn't it still be beneficial to have a long term expiration for good practice on that token as well?
Refresh Tokens are long-lived, Access Tokens are short-lived.
If I WERE to use a refresh token, would that token be persisted with the userId and/or JWT token?
It would be persisted as a separate token on the client, alongside JWT but not inside JWT. UserID/UID can be stored inside the JWT token itself.
When I update my token every 1 hour, how does this work? Will I want to create an endpoint that takes in my JWT token or my refresh token? Will this update the expiration date of my original JWT token, or create a new token?
Yes, you need a separate service that issues and refreshes token. It won't update the expiration of the existing JWT Token. A token is simply JSON field-value pairs that are base64 encoded. So changing the data, changes the output. The token also has the issue date, which will at the very least change on every fresh issue (refresh). So every token will be unique and new. The old tokens will auto-expire, hence you need expiration on all Access Tokens, otherwise they will linger around forever.
The other answer here states that old tokens get destroyed when you issue a new token. That's simply not the case. Tokens cannot be destroyed. In fact, you can harvest hundreds of tokens by constantly contacting the auth server and asking for new fresh tokens using your Refresh Token. Each of those Access Tokens will be valid till their expiry. So expiry is imperative, and it should be short.
Is there really the need for a refresh token given these details? It seems that If the user is just using a JWT token to grab a new token (per the link above) then the refresh token is obsolete.
JWT tokens have client claims. For example is_manager:true claim on a JWT token might allow access to manager-level features. Now if you decide to demote the user from manager to contractor, that won't take effect immediately. The user may still be using the old token. Finally when that expires, he hits the auth server to refresh his token. The auth server issues a new token without the managerial claim and the user won't be able to access managerial features any more. This creates a window during which the user's claims are not in sync with the server. This again explains why Access Tokens should be short-lived so sync'ing can happen often.
Essentially you are updating the authorization checks every 15 minutes, instead of checking them on every single request (which is how typical session-based auth works). If you want real-time permissions instead of every-15-minute refreshes, then JWT may not be a good fit.