Refresh access token before it expires using refresh token - android

I am working on an application, which uses OAuth - Token based authentication.
This is how the flow looks like, considering we have the access and refresh token.
Api call -> intercepter appends access-token -> api returns 200
Api call -> intercepter appends expired access-token -> api returns
401 -> intercepter refreshes token using refresh token ->
interceptor retries same req -> returns 200
Api call -> intercepter appends expired access-token -> api returns
401 -> intercepter refreshes token using refresh token(refresh token
is also expired) -> prompt guest to sign-in -> guest signed-in ->
retry request
This all works great and fine - I am considering to optimise it a bit i.e i don't want to call api and wait for 401 to return.
Instead check for token expiration beforehand, get the new access token and then call the api with valid token.
This approach of calculating the expiry of token using android system time might work - but can be misused sometimes when user changes the android time.
Wondering if there a better solution to avoid the expiry issue of time based on android system time.

Even if you add such a check in your code, you will still need that flow you presented in the question (so catching 401s and refreshing tokens accordingly). This is because, as you noticed, time settings on the client device can be changed, or there might be a slight clock skew between the client and the server (so no intentional tampering with time settings).
The approach where you check for expiry before the API call will work only if you have access to the expiration time of the access and refresh tokens. So either you received that information together with tokens and persisted it, or JWTs are used and you can easily check expiration.
Personally, I wouldn't add such a check unless there is some strong argument for it (e.g. you know that your app will be mainly used in remote locations with slow connections and you want to limit traffic to a minimum, etc.). The flow that you presented is a common one and works just fine.

Related

How to re use access token for future request and how to refresh access token Android Outlook API

In the example OutlookQuickStart for Android works fine in the first request after logon().Now I want to keep connect my app to that user and continue checking for new emails.. How can I re use the access token and build the request to check for new emails? Do I have to save the access token, refresh token ?
How I can refresh the token in Android if it is expired.
According to the documentation for the auth library at https://github.com/AzureAD/azure-activedirectory-library-for-android, the library caches the token and refresh token for you. So you would just use acquireTokenSilentSync to get the token each time you need it. That function would return the current token from the cache if it is still valid, and would refresh it if it is expired.
UPDATE: I've taken a closer look at the sample you're using and the Outlook SDK that it uses. The key thing here is the DependencyResolver object. You pass that object to the OutlookClient constructor. Then anytime you make an API call with that OutlookClient, it just calls the getCredentials override that you supply when you create the DependencyResolver.
So as the sample stands, you should be able to make multiple calls through that OutlookClient without having to change it at all. However, after an hour, when the access token expires, calls will start to fail. The fix for that would be to change the getCredentials override to always call acquireTokenSilentSync. Something like:
#Override
public Credentials getCredentials() {
logger.debug("getCredentials in resolver called");
AuthenticationResult result = mAuthContext.acquireTokenSilentSync(
scopes,
getResources().getString(R.string.AADClientId),
UserIdentifier.getAnyUser());
logger.debug("AcquireTokenSilentSync SUCCESS");
logger.debug("Token expires: ", result.getExpiresOn());
logger.debug("Token: ", result.getAccessToken());
return new OAuthCredentials(result.getAccessToken());
}
Caveat: I'm unable to run this code to validate it due to problems getting the Android emulator running on my dev machine :(.

Facebook Android SDK 4.1+

I'm upgrading to the latest Android and iOS sdks for Facebook and had two question.
Now that we have a concept of an access token that has to be refreshed periodically, I have been reading about the iOS SDK and noticed the below in the SDK:
/*!
#abstract Refresh the current access token's permission state and extend the token's expiration date,
if possible.
#param completionHandler an optional callback handler that can surface any errors related to permission refreshing.
#discussion On a successful refresh, the currentAccessToken will be updated so you typically only need to
observe the `FBSDKAccessTokenDidChangeNotification` notification.
If a token is already expired, it cannot be refreshed.
*/
+ (void)refreshCurrentAccessToken:(FBSDKGraphRequestHandler)completionHandler;
This method is for refreshing the SDK and is in the class FBSDKAccessToken. On the Android side I'm trying to find out if the same is true and read the code as well as documentation on this, it doesn't say if the AccessToken class's refresh method (refreshCurrentAccessTokenAsync) has to be called before expiration.
I have read this in the documentation:
https://developers.facebook.com/docs/reference/android/current/class/AccessToken/
Even for getLastRefresh() it says the below:
Gets the date at which the token was last refreshed. Since tokens expire, the Facebook SDK will attempt to renew them periodically.
This is unlike iOS where refreshing doesn't happen automatically. Is my assumption correct? That the iOS and Android sdks are handling refreshing differently?
Also, what is the best practice for refreshing tokens? I have been refreshing tokens in didFinishLaunchingWithOptions in iOS and on Android I do it when the application loads. However, it would help if there was more information on the best strategy with the SDKs.
I have been reading the following on this:
https://www.sammyk.me/access-token-handling-best-practices-in-facebook-php-sdk-v4
https://www.quora.com/With-the-Facebook-Graph-API-is-there-a-way-to-get-a-new-access-token-without-needing-to-re-enter-the-users-password
The access token will get refreshed automatically in the Android SDK if you make a graph request (it gets piggy-backed onto the request that you make).

ParseUser.getCurrentUser() confusion

I'm using Parse as the backend.
To check if the user is logged in I use ParseUser.getCurrentUser(). What I don't understand is, if the user changes his password from somewhere else (another device, the web-client), will this ParseUser return with some kind of error?
I don't think it does a check on the server, so I think it just returns the last saved user. This mean that I can continue to use this user (with an old password) or will I get a "wrong credential" response on the first request to the servers?
If I don't get it, will I at least get it when setting an ACL with parseObject.setACL(new ParseACL(ParseUser.getCurrentUser()));?
Try same action on yahoo in 2 open browsers of different types and see what you get?
Each client's been handed a token value by the respective servers and until the token expire will not be prompt for a new logon.
Well IMO Parse work very similar except the lease on Parse token never expire.
Response to the original parse logon contain the token value which the SDK may retain. Details are in the docs section on Rest api / user logon...
So, if a diff client change password but the token lease over on some other client never expire, the other client stays logged in.

Why I am getting exception after trying to access Box?

Some days ago I asked how to retain Box tokens (Load, save and use of authentication data in Box Android API). Now, when user wants to access his Box account I use this code to configure BoxAndroidClient:
client = new BoxAndroidClient(C, S);
client.authenticate(loadAuth()); //loadAuth() returns BoxAndroidOAuthData object
For short period of time after obtaining authentication data it works good. But after an hour or so I get an AuthFatalFailureException:
07-06 17:21:01.841: W/System.err(3647): com.box.boxjavalibv2.exceptions.AuthFatalFailureException
07-06 17:21:01.841: W/System.err(3647): at com.box.boxjavalibv2.authorization.OAuthDataController.doRefresh(OAuthDataController.java:275)
07-06 17:21:01.841: W/System.err(3647): at com.box.boxjavalibv2.authorization.OAuthDataController.refresh(OAuthDataController.java:191)
07-06 17:21:01.841: W/System.err(3647): at org.redscorpio.cloudtest.network.Box$2$1.run(Box.java:71)
Line 71 is
client.getOAuthDataController().refresh();
but it happens every time I need to access Box:
client.getFoldersManager().getFolderItems(current.getId(), LIST_REQUEST()).getEntries();
client.getFoldersManager().getFolder("0", DEFAULT_REQUEST);
I suspect that my token is invalidated at some point, but I don't know why it can't be renewed and why it happens after such a short period of time.
What I can do to prevent this?
I am not exactly sure what's going on. The sdk does auto refresh the token. However every time the token is refreshed, you actually will get a new refresh token and new access token, the old refresh token will not be valid any more. So basically the easiest way probably is update your stored OAuth token object every time your api call succeeds.
In the meantime, can you double check(maybe add some loggings) whether the stored refresh token and access token are the latest ones?
You can logcat out the access token in the code of token refresh:
com.box.boxjavalibv2.authorization.OAuthDataController class, doRefresh() method.
and in the place where api call is made: com.box.boxjavalibv2.authorization.OAuthAuthorization class, getAuthString() method.
When a user logs in and accepts your app's grant, you exchange the authorization_code for an access_token and a refresh_token (response shown below). The reason your token invalidates is that the access_token expires in one hour. You can exchange the refresh_token, which is valid for 14 days, for another one-hour access token. This is why you'll want the app to store both the access_token and the refresh_token, ensuring that a user will only need to re-authenticate if they return to the app after more than 14 days.
Using the refresh_token for another access_token will always return one more of each (refresh + access).
{
"access_token": "T9cE5asGnuyYCCqIZFoWjFHvNbvVqHjl",
"expires_in": 3600,
"token_type": "bearer",
"refresh_token": "J7rxTiWOHMoSC1isKZKBZWizoRXjkQzig5C6jFgCVJ9bUnsUfGMinKBDLZWP9BgR"
}

How to refresh Token in GoogleCredential

I have implement function retrieve credentials from saved token in SharedPreferences.
mCredential = new GoogleCredential.Builder()
.setClientSecrets(CLIENT_ID, CLIENT_SECRET)
.setJsonFactory(mJsonFactory)
.setTransport(mHttpTransport).build();
mCredential.setRefreshToken(accessRefreshTokenSave);
mCredential.setAccessToken(accessTokenSave);
Long expires = mCredential.getExpiresInSeconds();
boolean result = mCredential.refreshToken();
When the token is expired. We should call mCredential.refreshToken() to refresh the token, is it right ?
When i call refreshToken i got exception.
com.google.api.client.auth.oauth2.TokenResponseException: 400 Bad Request
{
"error" : "invalid_grant"
}
What should i need to do to refresh the token ? I found some document in Using OAuth 2.0 say about refresh token. But i don't know how to implement it in Android code? Is there any sample code do this ?
Generally (in my experience, since I haven't found any documentation) 'invalid grant' means there is some problem with your stored refresh token. This includes (I think):-
The user has revoked it
Your testing has caused multiple refresh tokens to be generated. Only 25 may be extant
The scopes associated with the stored token have changed
To recover the situation, delete the stored refresh token and start the process again. The good news, is that apart from the user revocation scenario (1) this is a testing environment issue and doesn't necessarily mean you have a bug.
Have a look on https://developers.google.com/+/mobile/android/sign-in that's the OAUTH for Android, and you can check what is wrong, or maybe use the example code in your Project. To give you more details, you have to post the entire project (linking it to GitHub for example) or post the interested Class ;-)

Categories

Resources