Google sign-in fails on an iOS PWA saved to Home Screen
Why Firebase Google sign-in rejects redirect and hangs on popup once a web app is saved to an iPhone Home Screen, straight from the engineer who answered the issue.
TL;DR#
A web app saved to an iPhone or iPad Home Screen opens inside Safari's standalone container, which runs on WKWebView — and Google has refused OAuth sign-in from embedded webviews like WKWebView since an August 2016 policy change. signInWithRedirect sends the user to a page Google treats as an unrecognised, insecure embedded browser; signInWithPopup opens the real Safari browser for the OAuth screen, but that popup cannot hand the result back to the Home Screen container because the two do not share web storage. There is no Firebase-side setting that fixes this: the restriction is enforced by Google's OAuth servers, not by the Firebase SDK.
Webview is not a "valid user agent"stuck in Safari about:blank, doesn't open the app again to pass on the tokenWhy it happens#
The report is firebase/firebase-js-sdk#77, opened in June 2017: saving a web app to an iOS Home Screen and then signing in with the Google Auth provider fails, by redirect or by popup, in two different ways. A Firebase engineer (bojeil-google, a contributor on the repository) answered directly on the thread:
"This is a known issue and not really Firebase related (in the case of redirect) which is Google sign-in related. Webviews are insecure and Google sign-in no longer works in that environment anymore. Google sign-in recommends using SFSafariViewController for this but homescreen apps cannot run in a SFSafariViewController, instead they always run in a webview environment. As for popups, they won't work for a different reason since Firebase OAuth popup relies on web storage to pass the result back to the app. However homescreen apps do not share the same web storage as the system browser (which is how the popup is opened)."
Two distinct mechanisms, both rooted in the same fact — an iOS Home Screen web app is a WKWebView, not Safari itself:
- Redirect mode sends the whole window to Google's sign-in page. Google's August 2016 policy states Google "will no longer allow OAuth requests to Google in embedded browsers known as 'web-views', such as the WebView UI element on Android and UIWebView/WKWebView on iOS", recommending Chrome Custom Tabs on Android and
SFSafariViewControlleron iOS instead. A Home Screen web app cannot openSFSafariViewControllerfor its own navigation — it always stays inside its own WKWebView — so Google's servers reject the request. The user agent string of that WKWebView gives Google's OAuth endpoint the signal that it is an embedded webview, which later issue threads name thedisallowed_user_agenterror. - Popup mode opens a second window — the real Safari browser, outside the Home Screen container — to run the OAuth flow. That part works. The failure is on the way back:
signInWithPopupreads the result through shared web storage between the opener and the popup, and a Home Screen app's WKWebView storage is a separate sandbox from the system Safari browser that opened the popup. The popup finishes the Google sign-in and has the token, with no storage channel back into the app that opened it — so it sits onabout:blankand the Home Screen app never sees a result.
When the thread's author asked whether this meant it was "impossible", the same engineer confirmed it directly: "Unfortunately, it is currently impossible if you wish to use Google Sign in. If you are using other providers, you can use the recommended signInWithRedirect for that mode (it should work)." — because non-Google OAuth providers were not (at the time) enforcing the embedded-webview block the way Google's own identity servers were.
What changed, and what is still open in 2026#
The issue sat open for three years while reporters tracked, iOS version by iOS version, which release first let it work: broken on the older releases they tested, working again from a release that shipped roughly half a year after the report was filed. It was closed in May 2020 by a different Firebase team member with the single line "Closed, as the issue has been fixed" — the fix being a change in how Safari's WebKit handles the standalone browsing context's relationship to the system browser, not a Firebase SDK release. Nothing in the thread names a Firebase SDK version or commit that resolved it, so this article does not either.
The restriction itself — Google refusing OAuth from a webview user agent — never went away; only the specific Home Screen case stopped tripping it once WebKit's handling changed. That the restriction is still live shows in a 2023 report against the same SDK, firebase/firebase-js-sdk#7443: signInWithPopup on an iOS Home Screen web app fails with auth/network-request-failed whenever the Firebase project's authDomain is a custom domain rather than the default *.firebaseapp.com one. If your app sets a custom authDomain, that is the first thing to rule out — see the Firebase Google sign-in on Vercel article for how a custom authDomain changes where the sign-in helper and its redirect URI live.
Fix#
There is no code change inside a Firebase web app that reopens Google sign-in for the Home Screen webview case on an iOS version where it is genuinely blocked — the restriction is enforced by Google's OAuth servers checking the request's user agent, not by anything the Firebase SDK sends. Three things are worth doing, in this order.
-
Confirm it is actually this restriction, not the 2023 custom-domain bug. Check
authDomainin your Firebase config.javascriptconst config = { apiKey: '...', authDomain: 'your-project-id.firebaseapp.com', // not a custom domain projectId: '...', }; firebase.initializeApp(config);If
authDomainis already your project's defaultfirebaseapp.comvalue and the failure isauth/network-request-failed, that is the 2023 bug pattern from issue #7443, not the 2017 webview block — the fix there is keeping sign-in on the default domain, or applying the same/__/auth/handlerproxy covered in the custom authDomain article so the handler is reachable on your own domain too. -
Route Google sign-in through the system browser, not the Home Screen container. Detect the standalone context and send the user to a normal Safari tab to complete sign-in, rather than attempting it inside the installed web app:
javascriptconst isIosHomeScreen = 'standalone' in window.navigator && window.navigator.standalone; if (isIosHomeScreen) { // Open the sign-in flow in the system browser instead of this WKWebView. window.open('https://your-app.example.com/sign-in', '_blank'); } else { firebase.auth().signInWithRedirect(googleAuthProvider); }This does not make
signInWithPopuporsignInWithRedirectwork from inside the WKWebView; it moves the OAuth step to where Google will actually run it, and accepts that the user finishes sign-in in Safari rather than inside the installed app. -
Do not resurrect the
localStorage-token-in-the-URL workaround from the thread. Several reporters on the issue passed a base64-encoded copy oflocalStorageback to the Home Screen app through a URL parameter. The same Firebase engineer rejected it on the record: "Please do not rely on hackinglocalStorage. It is an implementation detail which we have the right to change. We have plans to migrate from it toindexedDB." Firebase's web SDK has since moved its persistence to IndexedDB, which breaks that exact hack outright, and keeping a long-lived auth token in a URL parameter is a bigger exposure than the sign-in friction it avoids.
If sign-in now proceeds but the popup never returns control to your app's own code, check whether a Cross-Origin-Opener-Policy header is isolating the popup's opener reference — a separate, newer failure mode covered in Cross-Origin-Opener-Policy blocks window.closed.
Verify the fix#
- On a real iPhone (the standalone container does not reproduce in desktop Safari's responsive mode), add the web app to the Home Screen, open it from there — not from a Safari tab — and attempt Google sign-in.
- Confirm
navigator.standaloneistrueinside that session (log it, or check in Safari's remote Web Inspector connected to the device) before trusting the branch that routes to the system browser. - If sign-in still fails with
auth/network-request-failedspecifically, re-checkauthDomainagainst issue #7443's pattern before assuming the webview restriction is the cause.
One email a month — the latest explained errors
What the site published that month — mostly Next.js, Supabase and Node errors, explained. You confirm by email; unsubscribe any time in one click.
The next error#
If Google sign-in succeeds through the system browser but the result still does not reach the Home Screen app's own JavaScript — the popup closes on its own but signInWithPopup's promise never resolves — that is the opener/storage gap the COOP header produces on current browsers, not the 2017 webview block: see Cross-Origin-Opener-Policy blocks window.closed. And if the popup closes when the user cancels but your UI takes visibly longer to recover, that is the SDK's own fixed delay before it rejects, covered in auth/popup-closed-by-user fires late.
A Home Screen PWA that genuinely needs Google sign-in to work for every user, on every iOS version, is choosing a platform constraint Google's own identity team has stated it will not lift for embedded webviews — plan the onboarding flow around a brief hop into the system browser rather than around a code fix that does not exist.
Frequently Asked Questions
Still stuck? Paste your error.
Paste the error message or stack trace — we check it against every fix and tool on the site.
Continue Reading
Firebase Google Sign-in on Vercel: Custom authDomain Fix
Keep the Next.js app on Vercel and make the Google sign-in screen name your own domain instead of the project-id.firebaseapp.com subdomain.
linkWithRedirect fails with the Auth emulator: 3 causes
Three different errors hide behind one symptom, and only one of them is about the emulator. Two were reproduced with linkWithRedirect against the emulator, the API key one with the emulator disconnected.
useEmulator disableWarnings: TS2554 Expected 1 arguments
Reproduced on firebase 8.10.1, 9.23.0 and 13.0.0: which declaration file rejects the options object, what disableWarnings really silences in each version, and the two fixes that compile.


