Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fetchAuthSession() throws SignedOutException #5896

Open
3 of 14 tasks
Alvish0407 opened this issue Feb 4, 2025 · 16 comments
Open
3 of 14 tasks

fetchAuthSession() throws SignedOutException #5896

Alvish0407 opened this issue Feb 4, 2025 · 16 comments
Assignees
Labels
pending-maintainer-response Pending response from a maintainer of this repository question A question about the Amplify Flutter libraries to-be-reproduced Issues that have not been reproduced yet, but have reproduction steps provided

Comments

@Alvish0407
Copy link

Alvish0407 commented Feb 4, 2025

Description

Expiration Duration:

  • idToken: 5 minutes
  • accessToken: 5 minutes
  • refreshToken: 1 day

The idToken and accessToken refresh successfully only once. After that, the user is logged out instead of the tokens continuing to renew as expected.

Error Details:

  • When calling Amplify.Auth.fetchAuthSession, the following error is thrown:
I/flutter (10123): 💡   "isSignedIn": false,  
I/flutter (10123): 💡   "userSub": "AWSErrorResult<String, SignedOutException> {\n  \"exception\": {\n    \"message\": \"No user is currently signed in\"\n  },\n  \"stackTrace\": null\n}",  
I/flutter (10123): 💡   "userPoolTokens": "AWSErrorResult<CognitoUserPoolTokens, SignedOutException> {\n  \"exception\": {\n    \"message\": \"No user is currently signed in\"\n  },\n  \"stackTrace\": null\n}",  
I/flutter (10123): 💡   "credentials": "AWSSuccessResult<AWSCredentials, AuthException> {\n  \"value\": {\n    \"access_key_id\": \"*****\",\n    \"secret_access_key\": \"*****\",\n    \"token\": \"*****  
I/flutter (10123): 💡   "identityId": "AWSSuccessResult<String, AuthException> {\n  \"value\": \"*****\"\n}"  

Related Discussion:
Previous conversation on GitHub

Categories

  • Analytics
  • API (REST)
  • API (GraphQL)
  • Auth
  • Authenticator
  • DataStore
  • Notifications (Push)
  • Storage

Steps to Reproduce

Steps to Reproduce:

  1. Configure Token Expiration Durations:

    • idToken: 5 minutes
    • accessToken: 5 minutes
    • refreshToken: 1 day
  2. Log in using email and password.

  3. Wait for 10-15 minutes to allow token expiration and renewal attempts.

  4. Fetch the user session using:

    Amplify.Auth.fetchAuthSession();
  5. Observe the error mentioned above, indicating that the user is logged out instead of the tokens being refreshed.

Screenshots

No response

Platforms

  • iOS
  • Android
  • Web
  • macOS
  • Windows
  • Linux

Flutter Version

3.24.1

Amplify Flutter Version

^2.3.0

Deployment Method

AWS CDK

Schema

@github-actions github-actions bot added pending-triage This issue is in the backlog of issues to triage pending-maintainer-response Pending response from a maintainer of this repository labels Feb 4, 2025
@Alvish0407 Alvish0407 changed the title **accessToken** and **idToken** refresh only once instead of renewing as every time *accessToken* and *idToken* refresh only once instead of renewing as every time Feb 4, 2025
@Alvish0407 Alvish0407 changed the title *accessToken* and *idToken* refresh only once instead of renewing as every time accessToken and idToken refresh only once instead of renewing as every time Feb 4, 2025
@Alvish0407
Copy link
Author

Future<String?> restoreSession() async {
  final session = await Amplify.Auth.fetchAuthSession(
    options: const FetchAuthSessionOptions(
      forceRefresh: true,
    ),
  );

  if (session.isSignedIn) {
    final user = await Amplify.Auth.getCurrentUser();

    return user.username;
  }

  return null;
}

Observations:

  • After logging in, performing a hot restart twice causes session.isSignedIn to return true, but await Amplify.Auth.getCurrentUser(); throws an AuthException.
  • Removing forceRefresh: true prevents this issue.

@Alvish0407
Copy link
Author

Future<String?> restoreSession() async {
final session = await Amplify.Auth.fetchAuthSession(
options: const FetchAuthSessionOptions(
forceRefresh: true,
),
);

if (session.isSignedIn) {
final user = await Amplify.Auth.getCurrentUser();

return user.username;

}

return null;
}

Observations:

  • After logging in, performing a hot restart twice causes session.isSignedIn to return true, but await Amplify.Auth.getCurrentUser(); throws an AuthException.
  • Removing forceRefresh: true prevents this issue.

Related to #441

@Alvish0407 Alvish0407 changed the title accessToken and idToken refresh only once instead of renewing as every time getCurrentUser() throws AuthException while fetchAuthSession().isSignedIn returns true Feb 4, 2025
@Alvish0407 Alvish0407 changed the title getCurrentUser() throws AuthException while fetchAuthSession().isSignedIn returns true fetchAuthSession() throws SignedOutException Feb 4, 2025
@Alvish0407
Copy link
Author

Result of calling Amplify.Auth.fetchAuthSession() after around 15mins.

Image

@tyllark
Copy link
Member

tyllark commented Feb 5, 2025

Hello @Alvish0407, thank you for taking the time to provide all of these details. We will attempt to reproduce the issue with your token expiration configuration and get back to you with our findings.

@github-actions github-actions bot removed the pending-maintainer-response Pending response from a maintainer of this repository label Feb 5, 2025
@tyllark tyllark self-assigned this Feb 10, 2025
@ekjotmultani
Copy link
Member

Hi @Alvish0407, I used the same token expirations as you described but have been unsuccessful in reproducing it, fethcing the auth session every 5 minutes for an hour, everything seemed to work fine. You marked that you deployed with the cdk, can you provide details on how exactly you configured amplify and provide your outputs/ config file with anything secret removed?

@Alvish0407
Copy link
Author

Thank you for your prompt response, @ekjotmultani. I appreciate it. Here’s the frontend configuration.
Here, (hidden) stands for 'secret removed'

switch (appFlavor) {
    case Flavor.prod:
      authenticationFlowType = 'USER_PASSWORD_AUTH';
      region = 'us-east-2';
      poolId = '${region}(hidden)';
      appClientId = '(hidden)';
      break;
    case Flavor.dev:
      authenticationFlowType = 'USER_SRP_AUTH';
      region = 'ca-central-1';
      poolId = '${region}(hidden)';
      appClientId = '(hidden)';
      break;
    default:
      authenticationFlowType = '';
      poolId = '';
      appClientId = '';
      region = '';
  }
{
      "UserAgent": "aws-amplify-cli/2.0",
      "Version": "1.0",
      "auth": {
          "plugins": {
              "awsCognitoAuthPlugin": {
                  "UserAgent": "aws-amplify-cli/0.1.0",
                  "Version": "0.1.0",
                  "IdentityManager": {
                      "Default": {}
                  },
                  "CognitoUserPool": {
                      "Default": {
                          "PoolId": "$poolId",
                          "AppClientId": "$appClientId",
                          "Region": "$region"
                      }
                  },
                  "Auth": {
                      "Default": {
                          "authenticationFlowType": "$authenticationFlowType"
                      }
                  },
                  "PinpointAnalytics": {
                      "Default": {
                          "AppId": "(hidden)",
                          "Region": "us-east-1"
                      }
                  },
                  "PinpointTargeting": {
                      "Default": {
                          "Region": "us-east-1"
                      }
                  }
              }
          }
      },
      "analytics": {
          "plugins": {
              "awsPinpointAnalyticsPlugin": {
                  "pinpointAnalytics": {
                      "appId": "(hidden)",
                      "region": "us-east-1"
                  },
                  "pinpointTargeting": {
                      "region": "us-east-1"
                  }
              }
          }
      },
      "api": {
          "plugins": {
              "awsAPIPlugin": {
                  "towtaledbackendgraph": {
                      "endpointType": "GraphQL",
                      "endpoint": "(hidden)",
                      "region": "ca-central-1",
                      "authorizationType": "API_KEY",
                      "apiKey": "(hidden)"
                  }
              }
          }
      }
    }

@github-actions github-actions bot added the pending-maintainer-response Pending response from a maintainer of this repository label Feb 12, 2025
@tyllark
Copy link
Member

tyllark commented Feb 13, 2025

Hello @Alvish0407, I've been unable to reproduce the issue as well. I modified my Configuration file to match your Auth definitions as closely as possible, but I'm still not having any luck. As a side note you seem to have duplicate PinpointAnalytics and PinpointTargeting fields defined within your configuration.

Could you please help us with the following:

  1. Please provide your Cognito UserPool cdk script, so we can align our backends as much as possible.
  2. Are you toggling between your prod and dev flavors without uninstalling the app first? Which flavor are you using to produce this issue?
  3. Can you uninstall your app then reinstall it with the following function called and awaited directly after configuring Amplify. If the function Succeeds could you please update it so that it reproduces the issue.
Future<void> _fetchAuthSessionTest(String username, String password) async {
  try {
    //Sign In
    final result = await Amplify.Auth.signIn(
      username: username,
      password: password,
      options: const SignInOptions(),
    );
    if (!result.isSignedIn) throw Exception('Sign in failed');

    //Wait 15 minutes
    await Future.delayed(const Duration(minutes: 15));

    //Refresh Session
    final session = await Amplify.Auth.fetchAuthSession(
      options: const FetchAuthSessionOptions(
        forceRefresh: true,
      ),
    );
    if (!session.isSignedIn) {
      throw Exception('Issue Reproduced - Access token didn\'t refresh');
    }

    //Verify user is still signed in
    try {
      final user = await Amplify.Auth.getCurrentUser();
      debugPrint('Success - $user is still signed in!');
    } on AuthException catch (e) {
      throw Exception('Issue Reproduced - User is not signed in - $e');
    } on Exception catch (e) {
      throw Exception('Unexpected Error - $e');
    }
  } on Exception catch (e) {
    debugPrint('Error: $e');
  }
}

@github-actions github-actions bot removed the pending-maintainer-response Pending response from a maintainer of this repository label Feb 13, 2025
@Alvish0407
Copy link
Author

Alvish0407 commented Feb 13, 2025

@tyllark Thank you for your response.

1. Please provide your Cognito UserPool cdk script, so we can align our backends as much as possible.

createCognitoUserPool(): cognito.IUserPool {
  if (APP_ENV_CONSTANTS.APP_ENV === 'dev') {
    return cognito.UserPool.fromUserPoolId(this, 'ExistingUserPool', APP_ENV_CONSTANTS.COGNITO_USER_POOL_ID);
  }

  const userMigrationLambda = this.createServiceLambda("UserMigrationLambda", {
    code: lambda.Code.fromAsset('src/cognito-auth/'),
    role: this.towtaledServiceLambdaRole,
    environment: {
      OLD_COGNITO_USER_POOL_ID: APP_ENV_CONSTANTS.OLD_COGNITO_USER_POOL_ID,
      OLD_COGNITO_REGION: APP_ENV_CONSTANTS.OLD_COGNITO_REGION,
      OLD_MOBILE_APP_CLIENT_ID: APP_ENV_CONSTANTS.OLD_MOBILE_APP_CLIENT_ID,
    },
    handler: 'user-migration.handler'
  })

  return new cognito.UserPool(this, `${APP_ENV_CONSTANTS.APP_PREFIX}-UserPool`, {
    userPoolName: `${APP_ENV_CONSTANTS.APP_PREFIX}-UserPool`,
    selfSignUpEnabled: true,
    autoVerify: { email: true },
    accountRecovery: cognito.AccountRecovery.PHONE_AND_EMAIL,
    userVerification: {
      emailStyle: cognito.VerificationEmailStyle.CODE,
    },
    lambdaTriggers: {
      userMigration: userMigrationLambda,
    },
    customAttributes: {
      'subscriptionStatus': new cognito.StringAttribute({ mutable: true }),
      'revenueCatID': new cognito.StringAttribute({ mutable: true }),
    },
    passwordPolicy: {
      requireLowercase: false,
      requireUppercase: false,
      requireDigits: false,
      requireSymbols: false,
    }
  });
}

createCognitoUserPoolClient(userPool: cognito.IUserPool): cognito.IUserPoolClient {
  
  if(APP_ENV_CONSTANTS.APP_ENV == "dev") {
    return cognito.UserPoolClient.fromUserPoolClientId(this, 'ExistingUserPoolClient', APP_ENV_CONSTANTS.MOBILE_APP_CLIENT_ID);
  }

  return userPool.addClient('MobileAppClient', {
    userPoolClientName: `${APP_ENV_CONSTANTS.APP_PREFIX}-MobileAppClient`,
    authFlows: {
      adminUserPassword: true,
      userPassword: true,
      userSrp: true,
      custom: true
    },
    accessTokenValidity: cdk.Duration.days(1),
    idTokenValidity: cdk.Duration.days(1),
    refreshTokenValidity: cdk.Duration.days(30),
  });
}

dev client auth flow

Image

@github-actions github-actions bot added the pending-maintainer-response Pending response from a maintainer of this repository label Feb 13, 2025
@Alvish0407
Copy link
Author

Alvish0407 commented Feb 13, 2025

2. Are you toggling between your prod and dev flavors without uninstalling the app first? Which flavor are you using to produce this issue?

Earlier, we encountered an issue only with the prod flavor. However, after configuring the dev flavor, we are also experiencing the same issue. I’ve tried both methods: toggling between prod and dev by uninstalling the app and switching flavors without uninstalling. As of now, we are using the dev flavor to reproduce the issue. The reason for this is that the prod flavor has a token expiration of 1 day, which makes it challenging to regenerate the token. Therefore, we have set the token expiration to 5 minutes in the dev flavor.

One thing I’ve noticed is that the token gets refreshed once, and after that, it throws a SignedOutException.

@Alvish0407
Copy link
Author

3. Can you uninstall your app then reinstall it with the following function called and awaited directly after configuring Amplify. If the function Succeeds could you please update it so that it reproduces the issue.

I attempted to reproduce the issue using the provided snippet, but I was unable to generate the problem. Even after modifying the snippet to align with my project’s configuration and following the steps that enable me to create the issue in my project, it remained unsuccessful.

I noticed an instance where the token continues to refresh immediately after the user logs in and persists within the same application session. As soon as I execute a hot restart, the token refreshes a maximum of once, and it subsequently throws a SessionExpired exception.

@ekjotmultani ekjotmultani added question A question about the Amplify Flutter libraries to-be-reproduced Issues that have not been reproduced yet, but have reproduction steps provided labels Feb 13, 2025
@github-actions github-actions bot removed the pending-triage This issue is in the backlog of issues to triage label Feb 13, 2025
@Alvish0407
Copy link
Author

Alvish0407 commented Feb 17, 2025

@ekjotmultani @tyllark What are some possible causes that could be throwing a SessionExpiredException? Since I’m not explicitly calling the SignOut method and haven’t seen any logs related to it.

@tyllark
Copy link
Member

tyllark commented Feb 18, 2025

@Alvish0407 Initially I thought the multiple backends or your Authentication flows (ALLOW_REFRESH_TOKEN_AUTH) could be the cause of the issue, but that was ruled out by your ability to get at least 1 successful refresh. Another consideration was if you had enabled token revocation, but that shouldn't be trigger by just a hot restart.

My current hunch is that we have a bug in our native layers where we "reconfigure/setup" during a hot restart. We had an issue related to hot restart earlier, where we had stale references to objects after a hot restart. I haven't had a chance to reproduce the issue with the cdk script you provided yet, but I will provide an update here once I do.

@github-actions github-actions bot removed the pending-maintainer-response Pending response from a maintainer of this repository label Feb 18, 2025
@Alvish0407
Copy link
Author

@tyllark Hello, It says "Refresh Token has been revoked"

Image

@github-actions github-actions bot added the pending-maintainer-response Pending response from a maintainer of this repository label Feb 18, 2025
@Alvish0407
Copy link
Author

Btw, I'm using AuthenticationFlowType.userPasswordAuth

final result = await Amplify.Auth.signIn(
      password: password,
      username: email.toLowerCase(),
      options: const SignInOptions(
        pluginOptions: CognitoSignInPluginOptions(
          authFlowType: AuthenticationFlowType.userPasswordAuth,
        ),
      ),
    );

@Alvish0407
Copy link
Author

@tyllark @ekjotmultani any luck?

@Alvish0407
Copy link
Author

Seems related #2260

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
pending-maintainer-response Pending response from a maintainer of this repository question A question about the Amplify Flutter libraries to-be-reproduced Issues that have not been reproduced yet, but have reproduction steps provided
Projects
None yet
Development

No branches or pull requests

3 participants