Repository navigation
Description
Describe the bug
When GetCredentialsForIdentity rejects the cached identity pool id with NotAuthorizedException ("Access to Identity 'us-east-1:…' is forbidden."), the plugin never evicts the cached identity id. The authorization state machine lands in .error(.sessionError(.notAuthorized, credentials)) with the poisoned credentials retained inside the error state, and every subsequent fetchAuthSession re-presents the exact same cached identity id:
FetchAuthSessionOperationHelper.fetchhandlescase .error(.sessionError(_, let credentials))by callingrefreshIfRequired(existingCredentials: credentials, …)— same blob, same identity id.InitializeRefreshSessionalways pairs the storedidentityIDwith the stored/refreshed tokens (.refreshCognitoUserPoolWithIdentityId,.refreshAWSCredentialsWithUserPool); there is no path that falls back to a freshGetIdafter the identity was rejected.
The error is terminal server-side (the identity is linked to a different login, disabled, or deleted), so the device retries forever and the session never recovers. For a signed-in user this surfaces as getUserSub() / getCognitoTokens() returning the forbidden error on every launch while isSignedIn stays true — a permanently wedged boot. The only recovery is app-side: call Amplify.Auth.signOut() (which deletes the whole credential blob) and force re-authentication.
This is the same defect class as aws-amplify/amplify-js#5696, which was fixed there by evicting the cached identity id when this error is received.
We verified this against production telemetry: affected devices (predominantly account switchers whose local state ended up holding an identity id from a previous account) hit the error on every boot, on multiple days, and never self-recover; devices on an app version that reacts to this error with an explicit signOut() recover immediately.
Steps To Reproduce
- Configure Auth with user pool + identity pool.
- Sign in; let the plugin store
userPoolAndIdentityPool(signedInData, identityID, credentials). - Arrange for the stored identity id to be rejected by Cognito — e.g. delete the identity in the identity pool console, or reproduce a state where the stored identity id belongs to a different login than the stored tokens.
- Call
Amplify.Auth.fetchAuthSession()(or relaunch) repeatedly.
Observed: every call performs GetCredentialsForIdentity with the same rejected identity id and fails with NotAuthorizedException ("Access to Identity … is forbidden"). The cached identity id is never discarded; no GetId with the current logins map is ever attempted.
Expected behavior
On NotAuthorizedException from GetCredentialsForIdentity, the plugin should evict the cached identity id and retry with a fresh GetId using the current logins map (mirroring the amplify-js fix in aws-amplify/amplify-js#5696). At minimum for the signed-in case, the terminal error should not permanently retain the rejected identity id in the credential store.
Amplify Framework Version
2.53.3
Amplify Categories
Auth
Dependency manager
Swift PM
Xcode version
26
Relevant log output
AuthError: notAuthorized
"Access to Identity 'us-east-1:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' is forbidden."
(identical on every fetchAuthSession / launch; never recovers without an explicit Amplify.Auth.signOut())Is this a regression?
No — reproduced on 2.53.3; the relevant code paths (FetchAuthSessionOperationHelper, InitializeRefreshSession, AuthorizationState.Resolver .error handling) have behaved this way for a long time.
Activity
cadivus commentedon Aug 31, 2026
Hi @garysmckiernan,
thanks for opening the issue! We are looking into it and will update you here.
github-actions commentedon Sep 1, 2026
This issue is now closed. Comments on closed issues are hard for our team to see.
If you need more assistance, please open a new issue that references this one.
If you wish to keep having a conversation with other community members under this issue feel free to do so.
fix(auth): Refresh rejected identity ID (aws-amplify#4281)