-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Description
Before opening, please confirm:
- I have searched for duplicate or closed issues and discussions.
- I have read the guide for submitting bug reports.
- I have done my best to include a minimal, self-contained set of instructions for consistently reproducing the issue.
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