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.
Related
In my Android app, I use AWS Cognito to allow my users to sign up and login. I configured my identity pool so it allows guest users (unauthenticated users) in my app.
So everytime my user logs in or logs out, I call the following code to get an identity ID:
CognitoCachingCredentialsProvider credentialsProvider = new CognitoCachingCredentialsProvider(
this,
"eu-central-1:12345678-1234-5678-9012-1234567890ab",
"eu-central-1");
credentialsProvider.clearCredentials();
credentialsProvider.getIdentityId();
When my user logs in, it creates a new identity the first time, then the user gets the same identity everytime he logs in. But everytime he logs out, a new identity is created, since he's now a "guest" user.
Is that the expected behavior? And if yes, how can I remove an unused identity programmatically (for example when the user logs in, so the "guest" identity is now useless, since a new one will be created when he logs out)?
Thanks for your help.
From the docs, we have:
getIdentityId() Gets the Cognito identity id of the user. The first time when this method is called, a network request will be made to retrieve a new identity id. After that it's saved in SharedPreferences.
clearCredentials() Destroy all the saved AWS credentials but not the identity Id.
so, the behavior you described is totally normal according to the docs.
Now, let's find an approach to deal with the problem.
if you want to continue with your proposition, and delete the identity programmatically after the logout, you can use deleteUser() method from AWSJavaSDK.
However, if you want to keep the same identity for the same user after the logout, you shouldn't clear the cache, cause the won't keep the user any trace of its identity.
I hope this will help.
I am using AWS Cognito as mu authentication provider for an android app and I have the refresh token expiration set for 30 days on my user pool.
The access token I receive is valid for up to 1 hour so I can automatically renew the users session by calling getCurrentUser() on the CognitoUserPool if the user leaves the app and comes back in within 1 hour.
However, I want to use the cached refresh token if the user comes back a few hours later so they don't need to constantly log back in. The CognitoUserPool documentation indicates that it will only use the refresh token if it is used while the access token is still active.
Doesn't this defeat the purpose of a refresh token, or is a refresh token meant to be used only while the access token is active?
If a refresh token can't be used to get a new session how do apps keep users logged in for day/weeks/months at a time? Do they store the password on the device?
Cognito SDK internally uses refresh token to refresh the current user session:
//get CognitoUser instance by passing userName or emailID
CognitoUser cognitoUser = cognitoUserPool.getUser(userName);
//simply get User Session again and in your authenticationHandler, handle userSession obtained
cognitoUser.getSessionInBackground(authenticationHandler);
getSessionInBackground will internally use the refresh token to generate a new session without the need of passing any password.
We have developed a mobile application (Android & iOS) which has custom login with limited session expiry time (3 days). The session will expire after 3 days and we are showing Login page to re-login.
But we don't want to show login page to the user. What are the best approach to do that.
Approach 1:
In the server side, do not set the expiry date to the generated session. So that session will not expire until user logged out.
Approach 2:
In UI, save the username & password in permanent storage like sqlite & etc. When the session expired (after 3 days in my case), UI has to send hidden login call to get new session id. In this case we will not redirect to login page.
How other mobile apps keep the session Id's alive till user logout.
Please suggest me any other best approach apart from above 2 approaches.
You can use following approach to solve your issue, I have faced same issue and used same approach :
Server should send a extra RefreshToken with your sessionId.
Or server should provide a different API to refresh your sessionId with that refreshToken.
So suppose you get “invalid token” error, then you need to follow following steps :
call RefreshToken API using last saved RefreshToken.
Server should refresh that sessionID & reset expiryTime to 3 days and reply you with new SessionID.
Server should create new RefreshToken at their end only whenever you logOut/login again And when 3 days expires(means user haven’t used app for 3 days so he should be logged out).
So you should be logout only when that RefreshToken expires.
you will get new sessionID and then use that for further requests & for that request on which you got that error.
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.
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"
}