TL;DR: The "Sign in with Google" form doesn't debounce clicks on the "Continue" button, so it can trigger multiple redirect callbacks, in our case causing 15% of signups to fail. We've since reproduced the issue with several other companies' signup flows.
What's the issue?
A few months ago we (Flat.app) noticed that a meaningful fraction of signups-via-Google to our SaaS product were failing. I recently found out why, so I'm sharing this PSA for anyone facing a similar problem.
If your app supports "Sign in with Google", it's likely that new signups will fail if, on Google's OAuth consent screen, a user clicks "Continue" more than once. The error will probably be inscrutable to the user, depending on your setup, so they may just give up instead of trying again. In our case, we were losing around 15% of signups!
I encountered this issue while investigating failed signups for our product, but I've also reproduced it with other popular products including ChatGPT, Doordash, Expedia, and Snyk, so I assume it's widespread.
Some of these products use Auth0, as do we, but others don't, and they still generate an error of one kind or another.
For Auth0 specifically, the error is "You may have pressed the back button, refreshed during login, opened too many login dialogs, or there is some issue with cookies, since we couldn't find your session. Try logging in again from the application and if the problem persists please contact the administrator." The error tries to be helpful by listing potential causes, but it fails to mention the actual cause. That's because Auth0 wasn't aware of this failure mode, based on my correspondence with them.
Why does this happen?
After a user clicks "Continue" the first time, Google will respond with a 302 to the callback URL, passing along the authorization code and replaying the OAuth 2.0 state param. If the user clicks "Continue" again, Google will respond again with a 302 to the callback URL. The browser will abort the first pending request and issue a new request to the callback URL. Importantly, the state param is, as it should be, the same in both requests, and it typically incorporates a nonce (see https://datatracker.ietf.org/doc/html/draft-ietf-oauth-security-topics#name-protecting-redirect-based-f). Since the nonce will already have been consumed by the first request, the second request will be rejected.
Why would a user click "Continue" twice?
Simple: poor UX in Google's consent screen. The "Continue" button provides almost no feedback that the click was registered, and the screen provides no feedback that any requests are pending. So, some users will naturally try again, especially if they're on a slow connection.
What can Google do?
Google could disable the "Continue" button with a loading indicator after the first click. That would ensure it's not possible to click it twice, and it would provide an improved UX by showing the user that something is happening.
Google's OAuth consent screen was redesigned at some point in the past few years. Allowing "Continue" to be clicked twice, with no visible feedback, may be an unintended regression.
What can I do?
Test this in your own application. Be sure to deauthorize your app before each test run so that you get the OAuth consent screen. You can do that in your Google account's Data & privacy section.
Also, check your logs for errors to see if you're losing signups. See if you can detect this scenario and, if so, provide a better experience to users, e.g., by acknowledging what caused the error and giving them a clearer path to continue.