Skip to content

feat(clerk-js): Add signUpIfMissing for SignIn#7749

Open
dmoerner wants to merge 14 commits intomainfrom
daniel/user-4596-sign_up_if_missing-support-custom-flow-with-captcha-in-sdk
Open

feat(clerk-js): Add signUpIfMissing for SignIn#7749
dmoerner wants to merge 14 commits intomainfrom
daniel/user-4596-sign_up_if_missing-support-custom-flow-with-captcha-in-sdk

Conversation

@dmoerner
Copy link
Contributor

@dmoerner dmoerner commented Feb 3, 2026

Description

We are building a new sign-in-or-sign-up flow compatible with strict enumeration protection. It is meant to complement our existing sign-in-or-sign-up flow.

Our current sign-in-or-sign-up flow is managed by the SDKs: We start with a sign in attempt, and on a 422 (when an account does not exist), we redirect to a sign up. The flow is thus: Sign In (422) -> Sign Up (200) -> Attempt Verifications for VerifiedAtSignUp identifiers (200). This is vulnerable to user enumeration attacks because the attacker sees the sign in to sign up redirect before they prove their identity by completing a verification.

When sign_up_if_missing is passed as a param when POSTing a sign in, instead we do the following: Sign In (200) -> Attempt Verification for Identifier (200) -> Return transferable identification -> Transfer to Sign Up. This is enumeration safe, because you only see if an account already existed or was created after you verify your identity.

This PR is the first step in SDK support for this new flow. We add support for the optional signUpIfMissing param on sign in. We also add captcha support for SignIn. This is all optional and currently in testing with custom components. Support in Clerk components will be in future PRs.

Implementation Notes:

  • To avoid adding dependencies between legacy and future code, we duplicate some logic between legacy and future classes. This matches existing patterns on SignUp.
  • Now that we support captcha on sign in, we need to make sure we don't show a second captcha after transfer. We modify the sign up captcha handling to skip captchas on such transfers. There's no corresponding logic in the sign in captcha handling because we don't do sign up to sign in transfers outside of the OAuth flow.
  • I deleted a pointless update of the strategy in transfer sign ups; the backend ignores strategies passed on transfers already so we do not need to set it in the SDK before making a request.

Fixes USER-4596

Checklist

  • pnpm test runs as expected.
  • pnpm build runs as expected.
  • [ ]

Type of change

  • 🐛 Bug fix
  • 🌟 New feature
  • 🔨 Breaking change
  • 📖 Refactoring / dependency upgrade / documentation
  • other:

Summary by CodeRabbit

  • New Features
    • SignIn.create now supports the sign_up_if_missing parameter, enabling seamless user sign-up fallback during sign-in.
    • CAPTCHA protection is automatically integrated into sign-in processes when required.
    • Browser locale is automatically detected and included in sign-in requests for improved localization.

We are building a new sign-in-or-sign-up flow compatible with strict
enumeration protection. It is meant to complement our existing
sign-in-or-sign-up flow.

Our current sign-in-or-sign-up flow is managed by the SDKs: We start
with a sign in attempt, and on a 422 (when an account does not exist),
we redirect to a sign up. The flow is thus: Sign In (422) -> Sign Up
(200) -> Attempt Verifications for VerifiedAtSignUp identifiers (200).
This is vulnerable to user enumeration attacks because the attacker sees
the sign in to sign up redirect before they prove their identity by
completing a verification.

When `sign_up_if_missing` is passed as a param when POSTing a sign in,
instead we do the following: Sign In (200) -> Attempt Verification for
Identifier (200) -> Create User and Session. (In future work this third
step will be modified to support adding additional information to the
user, either via AccountTransfer or Session Tasks). This is enumeration
safe, because you only see if an account already existed or was created
after you verify your identity.

This PR is the first step in SDK support for this new flow. We add
support for the optional `sign_up_if_missing` param on `SignIn`. We also
add captcha support for `SignIn`. This is all optional and currently in
testing with custom components. Support in Clerk components will be in
future PRs.
@changeset-bot
Copy link

changeset-bot bot commented Feb 3, 2026

🦋 Changeset detected

Latest commit: edc4fa1

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 20 packages
Name Type
@clerk/clerk-js Minor
@clerk/shared Minor
@clerk/chrome-extension Patch
@clerk/expo Patch
@clerk/agent-toolkit Patch
@clerk/astro Patch
@clerk/backend Patch
@clerk/expo-passkeys Patch
@clerk/express Patch
@clerk/fastify Patch
@clerk/localizations Patch
@clerk/msw Patch
@clerk/nextjs Patch
@clerk/nuxt Patch
@clerk/react-router Patch
@clerk/react Patch
@clerk/tanstack-react-start Patch
@clerk/testing Patch
@clerk/ui Patch
@clerk/vue Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel
Copy link

vercel bot commented Feb 3, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
clerk-js-sandbox Ready Ready Preview, Comment Feb 13, 2026 6:41pm

Request Review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 3, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This pull request adds CAPTCHA support to SignIn.create for the custom flow with sign_up_if_missing parameter. The SignIn.create method is now async and returns a Promise, injecting browser locale into requests and incorporating a runtime CAPTCHA flow that determines whether a CAPTCHA token is needed based on request parameters. Type definitions for SignInCreateParams and SignInFutureCreateParams have been updated to include new fields for locale, sign_up_if_missing, and CAPTCHA-related data. The CaptchaOptions action type has been expanded to include 'signin', and test coverage has been added to verify CAPTCHA behavior in various scenarios.

🚥 Pre-merge checks | ✅ 4 | ❌ 2
❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning Changes include modifications to SignUp.ts that remove CAPTCHA bypass logic unrelated to the stated sign_up_if_missing objective, representing scope creep beyond the primary feature. Review whether the SignUp.ts changes (removal of CAPTCHA bypass logic) are necessary for this PR or should be split into a separate issue. Clarify the rationale for this modification.
Merge Conflict Detection ⚠️ Warning ❌ Merge conflicts detected (10 files):

⚔️ packages/astro/src/integration/create-integration.ts (content)
⚔️ packages/clerk-js/src/core/resources/PublicUserData.ts (content)
⚔️ packages/clerk-js/src/core/resources/SignIn.ts (content)
⚔️ packages/clerk-js/src/core/resources/SignUp.ts (content)
⚔️ packages/clerk-js/src/core/resources/__tests__/PublicUserData.test.ts (content)
⚔️ packages/clerk-js/src/core/resources/__tests__/SignIn.test.ts (content)
⚔️ packages/clerk-js/src/utils/captcha/types.ts (content)
⚔️ packages/shared/src/types/json.ts (content)
⚔️ packages/shared/src/types/signInCommon.ts (content)
⚔️ packages/shared/src/types/signInFuture.ts (content)

These conflicts must be resolved before merging into main.
Resolve conflicts locally and push changes to this branch.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The PR successfully implements both key coding objectives from USER-4596: adding sign_up_if_missing parameter support for SignIn.create and implementing CAPTCHA support for the SignIn flow.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(clerk-js): Add signUpIfMissing for SignIn' directly and accurately describes the main change in this PR: adding support for the signUpIfMissing parameter to SignIn.create. The title is concise, clear, and specific about the primary feature being introduced.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

@pkg-pr-new
Copy link

pkg-pr-new bot commented Feb 3, 2026

Open in StackBlitz

@clerk/agent-toolkit

npm i https://pkg.pr.new/@clerk/agent-toolkit@7749

@clerk/astro

npm i https://pkg.pr.new/@clerk/astro@7749

@clerk/backend

npm i https://pkg.pr.new/@clerk/backend@7749

@clerk/chrome-extension

npm i https://pkg.pr.new/@clerk/chrome-extension@7749

@clerk/clerk-js

npm i https://pkg.pr.new/@clerk/clerk-js@7749

@clerk/dev-cli

npm i https://pkg.pr.new/@clerk/dev-cli@7749

@clerk/expo

npm i https://pkg.pr.new/@clerk/expo@7749

@clerk/expo-passkeys

npm i https://pkg.pr.new/@clerk/expo-passkeys@7749

@clerk/express

npm i https://pkg.pr.new/@clerk/express@7749

@clerk/fastify

npm i https://pkg.pr.new/@clerk/fastify@7749

@clerk/hono

npm i https://pkg.pr.new/@clerk/hono@7749

@clerk/localizations

npm i https://pkg.pr.new/@clerk/localizations@7749

@clerk/nextjs

npm i https://pkg.pr.new/@clerk/nextjs@7749

@clerk/nuxt

npm i https://pkg.pr.new/@clerk/nuxt@7749

@clerk/react

npm i https://pkg.pr.new/@clerk/react@7749

@clerk/react-router

npm i https://pkg.pr.new/@clerk/react-router@7749

@clerk/shared

npm i https://pkg.pr.new/@clerk/shared@7749

@clerk/tanstack-react-start

npm i https://pkg.pr.new/@clerk/tanstack-react-start@7749

@clerk/testing

npm i https://pkg.pr.new/@clerk/testing@7749

@clerk/ui

npm i https://pkg.pr.new/@clerk/ui@7749

@clerk/upgrade

npm i https://pkg.pr.new/@clerk/upgrade@7749

@clerk/vue

npm i https://pkg.pr.new/@clerk/vue@7749

commit: edc4fa1

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@packages/clerk-js/src/core/resources/SignIn.ts`:
- Around line 185-192: The code accesses nested properties on
SignIn.clerk.client without guarding signUp/verifications/externalAccount;
change the retrieval of strategy in the SignIn transfer branch to use safe
checks (e.g. optional chaining or explicit null checks) so you do const strategy
= SignIn.clerk.client?.signUp?.verifications?.externalAccount?.strategy and only
assign (finalParams as TransferParams).strategy = strategy as
TransferParams['strategy'] if strategy is not undefined/null; update the logic
inside the transfer block (related to shouldBypassCaptchaForAttempt and
finalParams assignment) to avoid any potential TypeError from missing
intermediate objects.
- Around line 621-629: The transfer branch accesses
SignIn.clerk.client!.signUp.verifications.externalAccount.strategy directly
which can throw if signUp/verifications/externalAccount is undefined; update the
condition inside the captchaOauthBypass check to use optional chaining (e.g.,
SignIn.clerk.client?.signUp?.verifications?.externalAccount?.strategy) and
compare safely (guarding null/undefined) so the predicate returns false when the
nested property is missing, ensuring the transfer path doesn't cause a runtime
error.

@dmoerner dmoerner changed the title feat(clerk-js): Add sign_up_if_missing for SignIn.create feat(clerk-js): Add sign_up_if_missing for SignIn Feb 13, 2026
finalParams = { ...finalParams, ...captchaParams };
}

if (finalParams.transfer && this.shouldBypassCaptchaForAttempt(finalParams)) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I cleaned up this code path, which is pointless: On a transfer, the backend already pulls the strategy from the transfer and ignores any strategy included in the query params. We don't need the SDK to also pull the strategy from the transfer and include it in the query params.

@dmoerner dmoerner changed the title feat(clerk-js): Add sign_up_if_missing for SignIn feat(clerk-js): Add signUpIfMissing for SignIn Feb 13, 2026
@dmoerner dmoerner requested review from brkalow and dstaley February 13, 2026 19:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant