#14900·amplify-js

`signInWithRedirect` cancelled on iOS Safari leaves `inflightOAuth` set — then `signIn()` hangs forever

Author: lilyreadmooCreated Jul 30, 2026Updated Jul 30, 2026
LabelsbugAuth

Before opening, please confirm:

JavaScript Framework

Next.js

Amplify APIs

Authentication

Amplify Version

v6

Amplify Categories

auth

Backend

Amplify Gen 2

Environment information

- `aws-amplify` `^6.18.0`
- **Mobile Safari on iOS** (plain web page)
- social provider (Apple), `signInWithRedirect({ provider: 'Apple', options: { prompt: 'SELECT_ACCOUNT' } })`

Describe the bug

Summary

On iOS, tapping "Sign in with Apple" presents the native iOS authorization sheet (Face ID / Touch ID) as an overlay — the page does not navigate or reload, so the JS context survives. When the user cancels that native sheet, Amplify never clears the inflightOAuth flag for this path. Every subsequent call that fetches tokens (signIn, getCurrentUser, fetchAuthSession) then stays pending forever — no resolve, no reject, no timeout. In our site the user switches to email login, presses submit, and the button spins indefinitely; only a full page reload recovers.

Root cause (from reading the bundled source)

  • signInWithRedirectoauthSignIn() calls oAuthStore.storeOAuthInFlight(true) + storeOAuthState + storePKCE, writing inflightOAuth / oauthState / oauthPKCE to storage.
  • The web openAuthSession just sets window.location.href and returns nothing, so the canceled / error handling in oauthSignIn is (by its own comment) "effective only in react-native" — it never runs on web.
  • inflightOAuth is only cleared by resolveAndClearInflightPromises(), called from completeOAuthFlow (success, URL has code+state) or handleFailure (which also dispatches signInWithRedirect_failure).
  • The only "user cancelled" recovery on web is cancelOAuthFlow.mjs's listenForOAuthFlowCancellation, which only fires on bfcache back-navigation (pageshow with event.persisted === true). A cancelled native sheet is neither a bfcache restore nor a navigation, so nothing clears the flag.
  • With the flag still set, TokenOrchestrator.waitForInflightOAuth() returns an inflight Promise that has no reject branch and no timeout; getTokens() awaits it first. signIn()assertUserNotAuthenticated()getCurrentUser()getTokens() → hangs. assertUserNotAuthenticated's try/catch cannot rescue a promise that never settles.

Expected behavior

  1. Give the waitForInflightOAuth inflight promise a timeout and/or a reject path, so an interrupted OAuth flow can never become a permanent, unrecoverable hang.
  2. Expose a public API to clear inflight OAuth state (equivalent to DefaultOAuthStore.clearOAuthInflightData()), so apps can recover without reaching into CognitoIdentityServiceProvider.* localStorage keys directly.
  3. Broaden the web cancel-recovery beyond bfcache pageshow (e.g. detect return via visibilitychange/focus when inflightOAuth is set and the URL has no code).

Current workaround (for others hitting this)

Before calling signIn()/signUp(), remove inflightOAuth / oauthPKCE / oauthState for the client from localStorage (only those three keys — not the token keys, so signed-in users aren't logged out).

Reproduction steps

  1. On an iPhone, open the login page in mobile Safari and tap the Apple login button → signInWithRedirect(...) (non-custom provider).
  2. The native iOS biometric / Apple sign-in sheet appears as an overlay. Cancel / dismiss it.
  3. The page is still there — no navigation, no reload, not a bfcache restore.
  4. Call any token-requiring API — e.g. signIn({ username, options: { authFlowType: 'USER_AUTH' } }).
  5. The promise never settles.

Verify: after step 2, all three of CognitoIdentityServiceProvider.<clientId>.oauthState, CognitoIdentityServiceProvider.<clientId>.oauthPKCE, and CognitoIdentityServiceProvider.<clientId>.inflightOAuth (= 'true') remain in localStorage, and no signInWithRedirect_failure Hub event is dispatched.

Code Snippet

No response

Log output

No response

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

Safari 17.6

Additional information and screenshots

No response