Skip to content

Amplify Auth logging out when no internet whilst refresh token is valid #14522

@mattiLeBlanc

Description

@mattiLeBlanc

Before opening, please confirm:

JavaScript Framework

Angular

Amplify APIs

Authentication, GraphQL API

Amplify Version

v6

Amplify Categories

api, auth

Backend

CDK

Environment information

 System:
    OS: macOS 15.6.1
    CPU: (10) arm64 Apple M1 Max
    Memory: 10.63 GB / 64.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 22.16.0 - /usr/local/bin/node
    Yarn: 1.22.18 - ~/.npm-global/bin/yarn
    npm: 8.19.1 - ~/.npm-global/bin/npm
    pnpm: 9.0.0 - ~/.npm-global/bin/pnpm
  Browsers:
    Chrome: 139.0.7258.139
    Safari: 18.6
  npmGlobalPackages:
    @angular/cli: 20.1.0
    @anthropic-ai/claude-code: 1.0.53
    angular-http-server: 1.10.0
    aws-cdk: 2.1020.2
    aws: 0.0.3-2
    envinfo: 7.13.0
    firebase-tools: 11.16.1
    nativescript: 8.2.3
    node-gyp: 8.4.1
    npm: 8.19.1
    pnpm: 9.0.0
    sass-migrator: 2.3.1
    yarn: 1.22.18

Describe the bug

My client is getting logged out whilst having a valid refresh token.

Currently I am sending IdToken to Appsync instead of AccessToken this way:

Amplify.configure(awsConfig.tvApp, {
API: {
GraphQL: {
headers: async () => {
try {
let currentSession = await fetchAuthSession();
// const tokenExpiry = currentSession.tokens.accessToken.payload.exp * 1000;
// const HALF_MINUTE = 30000;
// const now = new Date().getTime() + HALF_MINUTE;
// if (tokenExpiry <= now) {
// currentSession = await fetchAuthSession({ forceRefresh: true });
// console.log('============================= fetched a new token===================');
// }
if (currentSession.tokens) {
const idToken = currentSession.tokens.idToken?.toString();
return { Authorization: idToken };
} else {
// signOut();
return undefined
}
} catch (error) {
return undefined;
}
}
}
}
});

I have a long lived refresh token (100 years). Last night at 2.33 AM my laptop was closed, and my browser was minimised on my App page, logged in. When I opened this morning at 9AM there was a spinner on the page where it normally show a list of records. When I refreshed it was logged out. In my slacK I got and error reported:

Graphql Error running query getResidents. Authmode Cognito. Error: Unauthorized  Error: Graphql Error running query getResidents. Authmode Cognito. Error: Unauthorized 
    at W.handleError (https://indigo.resparke.com/main-EBSITDKI.js:489:10836)
    at W.console.error (https://indigo.resparke.com/main-EBSITDKI.js:489:10754)
    at https://indigo.resparke.com/main-EBSITDKI.js:59:16243

The access and refresh token were published with the error and the accessToken was expired. But the refresh token can't expire. Still I was logged out due to an issue in the amplify/auth package. Do you think my fetchAuthSession call is logging me out if Chrome cycles whilst there is no internet?

I asked ChatGPT and it tells me:

Short answer: it’s very likely not “logging you out,” but your header callback plus being offline is causing your first GraphQL call after wake to go out without a valid JWT, which AppSync replies to with Unauthorized. Your app then treats that as “logged out.”

What’s happening under the hood

Both ID token and access token expire together (typically ~1h). Your refresh token being “100 years” doesn’t keep you authenticated locally; it only means Cognito can issue new short‑lived tokens when the client asks.

When your laptop sleeps, Chrome throttles timers and your tab sits unchanged for hours. On resume, your first GraphQL call triggers headers: async () => ….

fetchAuthSession() will try to use the cached tokens and refresh if needed. If you’re offline (or network wakes slowly), the refresh call can fail/throw.

In your code, you catch and return undefined, so the request is sent without Authorization.

AppSync replies Unauthorized. Your UI likely interprets that as a sign‑out condition (or shows a spinner forever until you refresh).

The Slack log showing an expired access token just means “we tried with an expired/cached token or no token and got 401.” It doesn’t prove the refresh token expired (it didn’t).

I am wondering if this is due to my code, with returning an undefined in the Catch clause. Or is this an issue in the amplify Auth package; fetchAuthSession is executed whilst being offline, it cant connect, an error happens which is not caught or in my case I return an undefined, and Amplify auth decides to log me out.

Is it possible that Amplify/auth does NOT do a log out when not connected to the internet and there is a Refresh token available. I understand the validity of the refresh token can't be determined when offline, but at least you could give the refreshToken the benefit of the doubt and dont do a logout in the client before getting a definitive answer.

I was considering upgrading my cognito from Lite to the next level which allows me to add cusstom attributes to the accessToken so that I dont have to do this idToken swap.
Would that make my system more robust?
Because I am seeing this unauthorized error a lot triggered by actually paying customers which is for from ideal.

Expected behavior

If there is a refresh token and no internet connection, and fetchAuthSession is called but fails, do not call a logout.

Reproduction steps

-Set refresh token in cognito to be long lasting. Accesstoken expiry 15 min.
-log in to your app,
-wait for accessToken to expire
-go offline I guess, try to do a programmatic refresh to a page that does an api call

// in chrome console
history.pushState(null, '', '/your-path');
dispatchEvent(new PopStateEvent('popstate'));

-hopefully it will try to get a session, fail, and remove token?

Code Snippet

use :

Amplify.configure(awsConfig.tvApp, {
  API: {
    GraphQL: {
      headers: async () => {
        try {
          let currentSession = await fetchAuthSession();
          // const tokenExpiry = currentSession.tokens.accessToken.payload.exp * 1000;
          // const HALF_MINUTE = 30000;
          // const now = new Date().getTime() + HALF_MINUTE;
          // if (tokenExpiry <= now) {
          //   currentSession = await fetchAuthSession({ forceRefresh: true });
          //   console.log('============================= fetched a new token===================');
          // }
          if (currentSession.tokens) {
            const idToken = currentSession.tokens.idToken?.toString();
            return { Authorization: idToken };
          } else {
            // signOut();
            return undefined
          }
        } catch (error) {
          return undefined;
        }
      }
    }
  }
});

Log output

Graphql Error running query getResidents. Authmode Cognito. Error: Unauthorized Error: Graphql Error running query getResidents. Authmode Cognito. Error: Unauthorized
at W.handleError (https://indigo.resparke.com/main-EBSITDKI.js:489:10836)
at W.console.error (https://indigo.resparke.com/main-EBSITDKI.js:489:10754)
at https://indigo.resparke.com/main-EBSITDKI.js:59:16243

aws-exports.js

No response

Manual configuration

No response

Additional configuration

No response

Mobile Device

No response

Mobile Operating System

No response

Mobile Browser

No response

Mobile Browser Version

No response

Additional information and screenshots

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    AuthRelated to Auth components/categoryquestionGeneral question

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions