aws-amplify / amplify-android

The fastest and easiest way to use AWS from your Android app.
https://docs.amplify.aws/lib/q/platform/android/
Apache License 2.0
247 stars 117 forks source link

Token are not refreshed automatically and causing unauthorised user using amplify v2 #2920

Open sharadsmhaske opened 1 month ago

sharadsmhaske commented 1 month ago

Before opening, please confirm:

Language and Async Model

Kotlin

Amplify Categories

Authentication

Gradle script dependencies

```groovy // Put output below this line amplifyframeworkVersion = '2.21.1' implementation "com.amplifyframework:core:$amplifyframeworkVersion" implementation "com.amplifyframework:aws-auth-cognito:$amplifyframeworkVersion" implementation "com.amplifyframework:aws-storage-s3:$amplifyframeworkVersion" implementation "com.amazonaws:aws-android-sdk-appsync:$awsappsyncVersion" ```

Environment information

``` # Put output below this line ```

Please include any relevant guides or documentation you're referencing

Amplify v2 documentation

Describe the bug

We have setup following settings for our android client app in AWS access token - 5 min Id token - 5 min Refresh token - 365 days

Reproduction steps (if applicable)

  1. Install the app
  2. Login into app using Amplify v2 signIn
  3. Wait for expiry of 5 min and keep app in foreground
  4. Refresh call from AWS amplify library is not happening. We are getting getting unauthorised exception as token refresh is not happening automatically

Code Snippet

No response

Log output

--------- beginning of crash 2024-09-19 18:51:19.762 21950-22003 amplify:aw...AuthPlugin V Auth State Change: NotConfigured(id=) 2024-09-19 18:51:19.768 21950-22032 amplify:aw...AuthPlugin V Auth State Change: ConfiguringAuth(id=) 2024-09-19 18:51:19.769 21950-22005 amplify:aw...AuthPlugin V InitAuthConfig Starting execution 2024-09-19 18:51:19.773 21950-22005 amplify:aw...AuthPlugin V Credential Store State Change: NotConfigured(id=) 2024-09-19 18:51:19.774 21950-22036 amplify:aw...AuthPlugin V Credential Store State Change: MigratingLegacyStore(id=) 2024-09-19 18:51:19.775 21950-22005 amplify:aw...AuthPlugin V MigrateLegacyCredentials Starting execution 2024-09-19 18:51:19.849 21950-22005 amplify:aw...AuthPlugin V MigrateLegacyCredentials Sending event LoadCredentialStore 2024-09-19 18:51:19.851 21950-22036 amplify:aw...AuthPlugin V Credential Store State Change: LoadingStoredCredentials(id=) 2024-09-19 18:51:19.852 21950-22005 amplify:aw...AuthPlugin V LoadCredentialStore Starting execution 2024-09-19 18:51:20.169 21950-22005 amplify:aw...AuthPlugin V LoadCredentialStore Sending event CompletedOperation 2024-09-19 18:51:20.193 21950-22036 amplify:aw...AuthPlugin V Credential Store State Change: Success(storedCredentials=UserAndIdentityPool(signedInData=SignedInData(userId=, username=, signedInDate=Thu Sep 19 18:42:30 GMT+05:30 2024, signInMethod=ApiBased(authType=USER_SRP_AUTH), cognitoUserPoolTokens=CognitoUserPoolTokens(idToken = eyJra, accessToken = eyJra, refreshToken = eyJjd)), identityId=, credentials=AWSCredentials(accessKeyId =**, secretAccessKey =, sessionToken =, expiration = 1726755640))) 2024-09-19 18:51:20.198 21950-22005 amplify:aw...AuthPlugin V MoveToIdleState Starting execution 2024-09-19 18:51:20.199 21950-22005 amplify:aw...AuthPlugin V MoveToIdleState Sending event MoveToIdleState 2024-09-19 18:51:20.200 21950-22036 amplify:aw...AuthPlugin V Credential Store State Change: Idle(id=) 2024-09-19 18:51:20.202 21950-22005 amplify:aw...AuthPlugin V InitAuthConfig Sending event ConfigureAuthentication 2024-09-19 18:51:20.204 21950-22032 amplify:aw...AuthPlugin V Auth State Change: ConfiguringAuthentication(authNState=NotConfigured(id=)) 2024-09-19 18:51:20.206 21950-22005 amplify:aw...AuthPlugin V InitAuthNConfig Starting execution 2024-09-19 18:51:20.207 21950-22005 amplify:aw...AuthPlugin V InitAuthNConfig Sending event Configure 2024-09-19 18:51:20.209 21950-22032 amplify:aw...AuthPlugin V Auth State Change: ConfiguringAuthentication(authNState=Configured(id=)) 2024-09-19 18:51:20.211 21950-22005 amplify:aw...AuthPlugin V ConfigureAuthN Starting execution 2024-09-19 18:51:20.213 21950-22005 amplify:aw...AuthPlugin V Credential Store State Change: Idle(id=) 2024-09-19 18:51:20.214 21950-22036 amplify:aw...AuthPlugin V Credential Store State Change: LoadingStoredCredentials(id=) 2024-09-19 18:51:20.215 21950-22005 amplify:aw...AuthPlugin V LoadCredentialStore Starting execution 2024-09-19 18:51:20.224 21950-22005 amplify:aw...AuthPlugin V LoadCredentialStore Sending event CompletedOperation 2024-09-19 18:51:20.225 21950-22036 amplify:aw...AuthPlugin V Credential Store State Change: Success(storedCredentials=DeviceData(deviceMetadata=com.amplifyframework.statemachine.codegen.data.DeviceMetadata$Empty@e38942f)) 2024-09-19 18:51:20.226 21950-22005 amplify:aw...AuthPlugin V MoveToIdleState Starting execution 2024-09-19 18:51:20.227 21950-22005 amplify:aw...AuthPlugin V MoveToIdleState Sending event MoveToIdleState 2024-09-19 18:51:20.228 21950-22036 amplify:aw...AuthPlugin V Credential Store State Change: Idle(id=) 2024-09-19 18:51:20.230 21950-22005 amplify:aw...AuthPlugin V ConfigureAuthN Sending event InitializedSignedIn 2024-09-19 18:51:20.231 21950-22005 amplify:aw...AuthPlugin V ConfigureAuthN Sending event ConfiguredAuthentication 2024-09-19 18:51:20.232 21950-22032 amplify:aw...AuthPlugin V Auth State Change: ConfiguringAuthentication(authNState=SignedIn(signedInData=SignedInData(userId=, username=, signedInDate=Thu Sep 19 18:42:30 GMT+05:30 2024, signInMethod=ApiBased(authType=USER_SRP_AUTH), cognitoUserPoolTokens=CognitoUserPoolTokens(idToken = eyJra, accessToken = eyJra, refreshToken = eyJjd)), deviceMetadata=com.amplifyframework.statemachine.codegen.data.DeviceMetadata$Empty@e38942f)) 2024-09-19 18:51:20.235 21950-22032 amplify:aw...AuthPlugin V Auth State Change: ConfiguringAuthorization(authNState=SignedIn(signedInData=SignedInData(userId=, username=, signedInDate=Thu Sep 19 18:42:30 GMT+05:30 2024, signInMethod=ApiBased(authType=USER_SRP_AUTH), cognitoUserPoolTokens=CognitoUserPoolTokens(idToken = eyJra, accessToken = eyJra, refreshToken = eyJjd)), deviceMetadata=com.amplifyframework.statemachine.codegen.data.DeviceMetadata$Empty@e38942f), authZState=NotConfigured(id=)) 2024-09-19 18:51:20.236 21950-22005 amplify:aw...AuthPlugin V InitAuthZConfig Starting execution 2024-09-19 18:51:20.237 21950-22005 amplify:aw...AuthPlugin V InitAuthZConfig Sending event CachedCredentialsAvailable 2024-09-19 18:51:20.241 21950-22032 amplify:aw...AuthPlugin V Auth State Change: ConfiguringAuthorization(authNState=SignedIn(signedInData=SignedInData(userId=, username=, signedInDate=Thu Sep 19 18:42:30 GMT+05:30 2024, signInMethod=ApiBased(authType=USER_SRP_AUTH), cognitoUserPoolTokens=CognitoUserPoolTokens(idToken = eyJra, accessToken = eyJra, refreshToken = eyJjd)), deviceMetadata=com.amplifyframework.statemachine.codegen.data.DeviceMetadata$Empty@e38942f), authZState=SessionEstablished(amplifyCredential=UserAndIdentityPool(signedInData=SignedInData(userId=3e69e6d1-5b03-4402-8698-9508cb9be45a, username=*, signedInDate=Thu Sep 19 18:42:30 GMT+05:30 2024, signInMethod=ApiBased(authType=USER_SRP_AUTH), cognitoUserPoolTokens=CognitoUserPoolTokens(idToken = eyJra, accessToken = eyJra, refreshToken = eyJjd)), identityId=, credentials=AWSCredentials(accessKeyId =**, secretAccessKey =, sessionToken =, expiration = 1726755640)))) 2024-09-19 18:51:20.242 21950-22005 amplify:aw...AuthPlugin V ConfigureAuthZ Starting execution 2024-09-19 18:51:20.242 21950-22005 amplify:aw...AuthPlugin V ConfigureAuthZ Sending event ConfiguredAuthorization 2024-09-19 18:51:20.245 21950-22032 amplify:aw...AuthPlugin V Auth State Change: Configured(authNState=SignedIn(signedInData=SignedInData(userId=, username=, signedInDate=Thu Sep 19 18:42:30 GMT+05:30 2024, signInMethod=ApiBased(authType=USER_SRP_AUTH), cognitoUserPoolTokens=CognitoUserPoolTokens(idToken = eyJra, accessToken = eyJra, refreshToken = eyJjd)), deviceMetadata=com.amplifyframework.statemachine.codegen.data.DeviceMetadata$Empty@e38942f), authZState=SessionEstablished(amplifyCredential=UserAndIdentityPool(signedInData=SignedInData(userId=, username=, signedInDate=Thu Sep 19 18:42:30 GMT+05:30 2024, signInMethod=ApiBased(authType=USER_SRP_AUTH), cognitoUserPoolTokens=CognitoUserPoolTokens(idToken = eyJra, accessToken = eyJra, refreshToken = eyJjd)), identityId=, credentials=AWSCredentials(accessKeyId =**, secretAccessKey =, sessionToken =***, expiration = 1726755640))))

amplifyconfiguration.json

No response

GraphQL Schema

```graphql // Put your schema below this line ```

Additional information and screenshots

No response

phantumcode commented 1 month ago

@sharadsmhaske Thanks for submitting your issue, we'll work on reproducing the issue.

phantumcode commented 1 month ago

@sharadsmhaske is the token getting refreshed if you call Amplify.Auth.fetchAuthSession?

sharadsmhaske commented 1 month ago

@phantumcode Yes if we call it explicitly. Also logs attached here are when user is logged in, after 5 minute expiry, nothing happened.

sharadsmhaske commented 1 month ago

@phantumcode FYI Same issue is there in iOS amplify version as well. Token are not refreshing automatically.

phantumcode commented 1 month ago

@sharadsmhaske Can you provide your amplify configuration file with sensitive details redacted as well a sample app/code that demonstrates your usage?

Also, what happens if you call fetchAuthSession with forceRefresh option set to true?

sharadsmhaske commented 1 month ago

@phantumcode I will provide it tomorrow the config file.

Also, what happens if you call fetchAuthSession with forceRefresh option set to true? - Same token is return after the expiry even if we set the force refresh when user sign in. We havent called after expiry as if we call after expiry with normal fetchauthsession also give fresh id token.

sharadsmhaske commented 1 month ago

@phantumcode Adding the content of amplify configuration.json file below

{ "auth": { "plugins": { "awsCognitoAuthPlugin": { "IdentityManager": { "Default": {} }, "CredentialsProvider": { "CognitoIdentity": { "Default": { "PoolId": "", "Region": "" } } }, "CognitoUserPool": { "Default": { "PoolId": "", "AppClientId": "", "Region": "" } }, "S3TransferUtility": { "Default": { "Bucket": "", "Region": "" } }, "Auth": { "Default": { "OAuth": { "WebDomain": “”, "AppClientId": "", "SignInRedirectURI": “”, "SignOutRedirectURI": "", "Scopes": [ "phone", "email", "openid", "profile", "aws.cognito.signin.user.admin" ] }, "authenticationFlowType": "USER_SRP_AUTH" } } } } }, "storage": { "plugins": { "awsS3StoragePlugin": { "bucket": "", "region": “” } } } }

We are using below API for user login Amplify.Auth.signIn( username, password, { authResult -> validateSignInConfirmation(authResult, restCallBack) }, { error -> val errorData = ErrorCode(null, error.message) restCallBack.onError(errorData, null) } )

For fetching user session Amplify.Auth.fetchAuthSession( { authSession -> val cognitoSession = authSession as AWSCognitoAuthSession restCallBack.onSuccess(cognitoSession) }, { val errorData = ErrorCode(null, it.message) restCallBack.onError(errorData, null) } )

For reading idtoken we are using authsession object returned in fetchSession api authSession?.tokensResult?.value?.idToken.toString()

phantumcode commented 1 month ago

Thanks, we'll work work on reproducing the issue.

phantumcode commented 1 month ago

As a clarification, the tokens does not refresh automatically if there are no api calls. The tokens are refreshed when an Amplify api is executed and the executed api internally calls fetchAuthSession.

phantumcode commented 1 month ago

@sharadsmhaske I'm not seeing any issues with expired session getting refreshed. Once the tokens are expired, the tokens will be refreshed upon calling fetchAuthSession or any any other Amplify api that executes fetchAuthSession internally. The tokens will not be refreshed automatically by itself while the app is in idle state.

sharadsmhaske commented 1 month ago

@phantumcode We are using authsession object to get id token that is used as authorization header for all the apis through aws api gateway. As you are saying it wont auto refresh, then we might need to call this api each time when we need refresh the token. This is contracting to facts that aws amplify auto manage token refresh. How to handle this scenario? Also there is no way to know whether token is about to expire. I think SDK should provide some mechanism to let the client to know so that only one call can be made to refresh it.

phantumcode commented 1 month ago

@sharadsmhaske You can listen to the Amplify Hub Event for when a session has expired or handle a SessionExpiredException and call fetchAuthSession to refresh

sharadsmhaske commented 1 month ago

@phantumcode We have some api which might get failed because of token is expired. Can you please elaborate how we will get sessionexpiredexception when reading the idtoken only in amplify.

phantumcode commented 1 month ago

@sharadsmhaske Are the APIs you're calling Amplify APIs or your custom APIs? Amplify Auth apis will call fetchAuthSession internally, so any expired tokens will be automatically refreshed. Otherwise you'll need to check the service exception being returned and check the exception type and determine if it's a not authorized exception or the cause of the exception is due to session expiration and then call fetchAuthSession to refresh the tokens as a result of the service exception. Alternatively, you can call fetchAuthSession ahead of time to ensure that your sessions are always fresh before your service call.

tylerjroach commented 1 week ago

Can you check your dependencies? I think your usage of the AWS AppSync SDK with Amplify v2 is likely problematic. I believe the AppSync SDK will attempt to use AWS Android SDK's MobileClient which is incompatible with Amplify v2 as it wipes Amplify v2 credentials stored on device (which would cause the loss of tokens).

If you want to use AWS AppSync SDK with Amplify v2, you will need to use a custom credentials provider and pass that in. See this page https://docs.amplify.aws/gen1/android/sdk/configuration/amplify-compatibility/ for instructions on how to create a CredentialsProvider that uses Amplify v2.