signUp.finalize() lacks the stale-client reload guard that signIn.finalize() has — FAPI propagation lag becomes a silent sign-out
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 2/5
- Tiempo estimado
- 1-3 horas
- Aptitud para principiantes
- 82/100
- Tipo de issue
- Error
- Claridad
- Bien especificado
- Estado de actividad
- Activo
- Stack tecnológico
- typescript
- Área
- authentication
Línea de trabajo
Comienza comparando SignInFuture.finalize() en packages/clerk-js/src/core/resources/SignIn.ts con SignUpFuture.finalize() en packages/clerk-js/src/core/resources/SignUp.ts; después, revisa la resolución de sesiones en packages/clerk-js/src/core/clerk.ts. Verifica el escenario de un cliente obsoleto en el que createdSessionId no está presente en client.sessions. Se considera terminado cuando la finalización del registro gestiona ese retraso igual que el inicio de sesión y deja de cerrar la sesión del usuario silenciosamente.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
Preliminary checks
- I have reviewed the documentation and existing issues; I could not find this reported (searched for
setActive+client.reload, "sessions.some", and the SignIn guard's comment text).
Package + version
@clerk/clerk-js (observed via @clerk/expo on React Native; verified present on main as of 2026-08-11)
Description
SignUpFuture.finalize() is missing the stale-client reload guard that SignInFuture.finalize() has. On a phone-OTP sign-up, FAPI propagation lag between the verification response and the piggybacked Client turns a successful sign-up into a silent sign-out.
Mechanism:
setActive({ session: createdSessionId })resolves a string session id against the local client and coerces a miss tonull:
// packages/clerk-js/src/core/clerk.ts
if (typeof session === 'string') {
session = (this.client.sessions.find(x => x.id === session) as SignedInSessionResource) || null;
}
…and setActive({ session: null }) is the sign-out path. So a session id that is real on the server but not yet visible in the in-memory client is treated as "sign out", with no error surfaced to the caller.
SignInFuture.finalize()protects against exactly this with a client reload (packages/clerk-js/src/core/resources/SignIn.ts, ~L1538):
// Reload the client if the created session is not in the client's sessions. This can happen during modal SSO
// flows where the in-memory client does not have the created session.
if (SignIn.clerk.client && !SignIn.clerk.client.sessions.some(s => s.id === this.#resource.createdSessionId)) {
await SignIn.clerk.client.reload();
}
this.#canBeDiscarded = true;
await SignIn.clerk.setActive({ session: this.#resource.createdSessionId, navigate });
SignUpFuture.finalize()has no such guard (packages/clerk-js/src/core/resources/SignUp.ts, ~L1224):
async finalize(params?: SignUpFutureFinalizeParams): Promise<{ error: ClerkError | null }> {
const { navigate } = params || {};
return runAsyncResourceTask(this.#resource, async () => {
if (!this.#resource.createdSessionId) {
throw new Error('Cannot finalize sign-up without a created session.');
}
this.#canBeDiscarded = true;
await SignUp.clerk.setActive({ session: this.#resource.createdSessionId, navigate });
});
}
The stale-client condition the SignIn comment describes is not SSO-specific — on mobile (Expo / React Native, phone-code strategy) the verification response's piggybacked client regularly lags the just-created session under real-world cellular latency, and sign-up is the flow where this hits hardest: it strikes brand-new users at the exact moment of a successful verification.
Real-world impact
Production React Native (Expo) app, phone-OTP-only auth. Before we wrapped finalize with our own reload-until-visible guard app-side, roughly a quarter of new sign-ups over a 14-day window hit a stuck state downstream of this silent sign-out — the user lands on the next onboarding screen already signed out, and every subsequent getToken() throws Unable to authenticate the request, you need to supply an active session. After shipping the app-side guard, the error class disappeared from our telemetry entirely, which is strong evidence the reload guard is the correct fix.
Expected behavior
Either:
SignUpFuture.finalize()mirrors the SignIn guard (reload the client whencreatedSessionIdis not visible yet), orsetActive({ session: '<id>' })errors when the id cannot be resolved, instead of silently signing the user out.
Proposed fix
async finalize(params?: SignUpFutureFinalizeParams): Promise<{ error: ClerkError | null }> {
const { navigate } = params || {};
return runAsyncResourceTask(this.#resource, async () => {
if (!this.#resource.createdSessionId) {
throw new Error('Cannot finalize sign-up without a created session.');
}
+ // Reload the client if the created session is not in the client's sessions. Mirrors
+ // SignInFuture.finalize(): the in-memory client can lag the just-created session
+ // (modal SSO flows on web; piggybacked-client propagation lag on mobile).
+ if (SignUp.clerk.client && !SignUp.clerk.client.sessions.some(s => s.id === this.#resource.createdSessionId)) {
+ await SignUp.clerk.client.reload();
+ }
+
this.#canBeDiscarded = true;
await SignUp.clerk.setActive({ session: this.#resource.createdSessionId, navigate });
});
}
Related prior art for the same shared-client race family: #8548 (avoid re-preparing pending code verifications) and #9225 (coalesce concurrent first/second factor preparations).
Happy to open a PR with the change above if the approach looks right to the team.
- Lenguaje dominante
- TypeScript
- Estrellas
- 1.8k
- Forks
- 472
- Merge medio
- 2 d 8 h
- PR fusionados (30 d)
- 184
Guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de clerk/javascript
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 74/100
clerk/javascript#9611 · 1 comentario ·
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 86/100
clerk/javascript#9573 ·
-
Dificultad 4/5 3-5 días Aptitud para principiantes 64/100
clerk/javascript#9775 · 1 comentario ·
-
Dificultad 4/5 3-5 días Aptitud para principiantes 48/100
clerk/javascript#9770 · 3 comentarios ·
-
Dificultad 3/5 1-2 días Aptitud para principiantes 68/100
clerk/javascript#9667 · 1 comentario ·
Todos los issues de clerk/javascript
Issues similares
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
-
area:tools bug good first issue help wanted priority:P2
Dificultad 2/5 1-3 horas Aptitud para principiantes 90/100
TaewoooPark/Motifcode#14 ·
-
bug 🐞
Dificultad 2/5 1-3 horas Aptitud para principiantes 68/100
-
[Bounty proposal] fix(web): memory insights count an evening memory on the next day ($25 proposed) Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 84/100
BasedHardware/omi#15320 ·
-
Dificultad 2/5 Medio día Aptitud para principiantes 78/100
vercel/vercel-plugin#199 ·