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"
}
Related
I have been reading around on different ways to refresh the cognito session after 1 hour, and I have yet to get a conclusive answer from aws team or anyone else. How do you get new tokens after the sessions have expired without re-authenticating, that is, the user has to login again (enter their password/email credentials).
There is a method refresh() in CognitoCachingCredentialsProvider class, that I believe refreshes the session. However, after that is called how do you get the new tokens (idToken/accessToken/refreshToken)? In my case the refreshToken is set to the maximum expiration time which is about 10 years.
The only way to get new tokens as I have done so far, is through user authentication when the user is logging in, where cognitoUser.getSessionInBackground(authenticationHandler) is called. This interface provides the tokens retrieved from CognitioUserSession. It seems very counterproductive for my application in particular to prompt the user to login, using their password each time after 1 hour.
I would like to add one more thing, is it even possible to get new tokens after the idToken and accessToken have expired? Looking at the aws cognito raw code, I have not seen an interface that provides that outside of login in the user despite what the documentation says.
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 :(.
I have communicate with API using retrofit. When the user is log in, I save account to database and when the user go to app next time, I get data from database (so I skipped login screen). Problem is when user's token expires.
How to handle the situation?
in login fragment
PSEUDOCODE
user = ... //get user from database
if(user != null) {
startActivityAccountActivity();
}
//onButtonClick
emailLogin();
Don't go to your "logged in" activity just because you have a token saved, because as you have correctly noticed, it may be invalid. Try authenticating with the API when you get the token, and only go to the "logged in" activity if it indeed worked. Otherwise proceed as if there was no token saved (and remove the expired one from the database).
You should also note that the token may expire when the user is in the "logged in" activity. For example, the user logged in, used the app and then went to another app from the recents screen. A week later he/she returns to your app with the "logged in" activity open, but in the mean time the token has expired and nothing will work. So you should also check if the token still works there, maybe in the onStart() of the activity.
As indramurari said, you can also handle it on the backend if you control it. But keep in mind that it doesn't solve your inherent problem of handling expired tokens, a refresh token may also expire and you are back to square one. If you make refresh tokens not expire you can just make the login tokens not expire. (This paragraph would be a comment on his answer, but I don't have enough reputation.)
It depends on your back end security level. You have two options to handle this situation.
Build some mechanism on back end side so that your server will send some refresh-token along with the user's token at the time of login to Android device. Whenever user's token get expired then request from Android device to your server to obtain new user's token by sending old user's token along with refresh-token. And you can use that new user's token for future. Repeat this whenever user's token get expired.
Note - refresh-token is for validating if it is valid resource who is requesting for a user's token.
You can delete the user account from database and tell user to Re-Login.
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.
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 ;-)