handleRedirectCallback is not idempotent: SSO callback runs twice and the second signUp.create({ transfer: true }) fails with "There is no account to transfer"
Les mainteneurs répondent en général sous 1 jour
Personne n'a encore pris cette issue.
Évaluation
- Difficulté
- 4/5
- Temps estimé
- 3-5 jours
- Accessibilité débutants
- 45/100
- Type d'issue
- Bug
- Clarté
- Clairement spécifiée
- Activité
- Active
- Stack technique
- next.js, react, typescript
- Domaine
- authentication, backend-api-design
Piste de recherche
Start with the three named entry points: packages/ui/src/common/SSOCallback.tsx, packages/clerk-js/src/core/clerk.ts, and packages/react/src/isomorphicClerk.ts. Trace the callback effect and redirect handling, then locate tests for these paths and reproduce the duplicate call behavior. Done means repeated handling of one OAuth return does not create duplicate transfers and callback rejections reach the caller.
Rédigé par le modèle d'indexation à partir du texte de l'issue.
Description
Preliminary Checks
- I have reviewed the documentation: https://clerk.com/docs
- I have searched for existing issues: https://github.com/clerk/javascript/issues
- I have not already reached out to Clerk support via email or Discord (if you have, no need to open an issue here)
- This issue is not a question, general help request, or anything other than a bug report directly related to Clerk. Please ask questions in our Discord community: https://clerk.com/discord.
Reproduction
Source-level, see Description. No minimal repro: the double mount happens in real Chrome and Firefox but never in headless Chromium.
Publishable key
N/A
Description
After going from @clerk/nextjs 7.7.9 to 7.9.17, new users signing up with Google via the prebuilt <SignIn> started failing with "There is no account to transfer". Same clerk-js (6.39.0) before and after. Before: every new-user OAuth return sent one transfer. After: most sent two, and the second one failed.
Steps to reproduce:
- Prebuilt
<SignIn>on a path-routed page, Google OAuth on, legal consent required - Continue with Google using a Google account that has no Clerk user
- Finish Google consent, land on /sign-in/sso-callback
Expected behavior:
One POST /v1/client/sign_ups?transfer=true, then the legal consent step.
Actual behavior:
Two POST /v1/client/sign_ups?transfer=true, 4 to 200 ms apart. The first creates the sign-up (missing_requirements). The second fails with account_transfer_invalid and the user is sent back to sign-in. Once both succeeded and left two half done sign-ups.
The SignIn tree mounts twice. On a plain /sign-in load in real Chrome, useAutoFillPasskey sends two identical POST /v1/client/sign_ins in the same ms with different ids:
https://github.com/clerk/javascript/blob/6857df6841fb044f88e69f978917d8b8e8040d67/packages/ui/src/components/SignIn/SignInStart.tsx#L60
So SSOCallback calls handleRedirectCallback twice. Nothing stops the second call:
- SSOCallback runs it from a useEffect with no once guard, the cleanup only hides the error: https://github.com/clerk/javascript/blob/6857df6841fb044f88e69f978917d8b8e8040d67/packages/ui/src/common/SSOCallback.tsx#L28-L52
- _handleRedirectCallback has no in-flight dedupe, both calls see "transferable" and both call signUp.create({ transfer: true }): https://github.com/clerk/javascript/blob/6857df6841fb044f88e69f978917d8b8e8040d67/packages/clerk-js/src/core/clerk.ts#L2853-L2860
- IsomorphicClerk.handleRedirectCallback swallows the rejection, so a custom callback page using useClerk() can't see the failure. The comment there already names the fix ("making handleRedirectCallback idempotent"): https://github.com/clerk/javascript/blob/6857df6841fb044f88e69f978917d8b8e8040d67/packages/react/src/isomorphicClerk.ts#L1636-L1650
Workaround: own sso-callback page that calls window.Clerk.handleRedirectCallback once per callback URL per page load.
Ask:
- Make handleRedirectCallback idempotent per OAuth return (or dedupe in-flight calls)
- Let IsomorphicClerk pass the rejection through
Environment
@clerk/nextjs 7.9.17, @clerk/react 6.17.8, @clerk/shared 4.40.0, clerk-js 6.39.0 to 6.41.0, @clerk/ui 1.42.0, next 16.4.1, react 19.2.8, Chrome and Firefox (current stable)
- Langage dominant
- TypeScript
- Étoiles
- 1.8k
- Forks
- 483
- Merge moyen
- 1 j 20 h
- PR mergées (30 j)
- 363
Préparer son environnement
- Aucun Dockerfile ni fichier Docker Compose
- Propose un modèle de pull request
- Lire le guide de contribution
Par où commencer
- Lisez l'issue en entier, puis le guide de contribution du projet.
- Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
- Forkez le dépôt et travaillez sur une branche.
- Ouvrez une pull request qui référence le numéro de l'issue.
Autres issues de clerk/javascript
-
Difficulté 2/5 1-3 heures Accessibilité débutants 75/100
clerk/javascript#10548 ·
Les mainteneurs répondent en général sous 1 jour
-
Difficulté 2/5 1-3 heures Accessibilité débutants 84/100
clerk/javascript#10547 ·
Les mainteneurs répondent en général sous 1 jour
-
<SignIn />: first "Use email" click switches back to phone when `initialValues.phoneNumber` is setPeut-être pris @twicestruck l’a pris il y a 3 jours. Ouverte
Difficulté 2/5 1-3 heures Accessibilité débutants 74/100
clerk/javascript#10487 ·
Les mainteneurs répondent en général sous 1 jour
-
useLoadedIsomorphicClerk misses "ready" when a ClerkProvider remounts after clerk-js has loaded — <ClerkLoading> never resolvesPeut-être à nouveau libre Une pull request pour cette issue a été fermée sans être fusionnée. Ouverte
Difficulté 2/5 1-3 heures Accessibilité débutants 82/100
clerk/javascript#10462 ·
Les mainteneurs répondent en général sous 1 jour
-
ClerkAPIError drops meta.lockout_expires_in_seconds from user_locked errorsPeut-être pris @umeraamir69 l’a pris il y a 9 jours. Ouverte
Difficulté 2/5 1-3 heures Accessibilité débutants 78/100
clerk/javascript#10026 · 2 commentaires ·
Les mainteneurs répondent en général sous 1 jour
Toutes les issues de clerk/javascript
Issues similaires
-
Difficulté 2/5 1-3 heures Accessibilité débutants 85/100
components-web-app/docs#311 ·
-
Difficulté 2/5 1-3 heures Accessibilité débutants 82/100
NEARBuilders/everything-dev#678 ·
Les mainteneurs répondent en général sous 1 jour
-
Difficulté 1/5 1-3 heures Accessibilité débutants 90/100
formbricks/formbricks#9881 ·
Les mainteneurs répondent en général sous 1 jour
-
Difficulté 2/5 1-3 heures Accessibilité débutants 68/100
-
Difficulté 2/5 1-3 heures Accessibilité débutants 72/100
Les mainteneurs répondent en général sous 1 jour