Skip to content

fix(init): simplify auth/keyless flow and fix --starter#175

Open
rafa-thayto wants to merge 5 commits intomainfrom
rafa-thayto/more-init-fixes
Open

fix(init): simplify auth/keyless flow and fix --starter#175
rafa-thayto wants to merge 5 commits intomainfrom
rafa-thayto/more-init-fixes

Conversation

@rafa-thayto
Copy link
Copy Markdown
Contributor

@rafa-thayto rafa-thayto commented Apr 16, 2026

Summary

Four clerk init fixes on this branch:

  • Skip askSkipAuth and keyless flow when signed in. If the user has an OAuth token, clerk init goes straight to the authenticated flow (auth + link + env pull).
  • Count CLERK_PLATFORM_API_KEY as authenticated. Non-interactive / CI runs with an API key no longer fall through to keyless mode. A new isAuthenticated() helper covers both OAuth tokens and the env var.
  • Remove the "Skip authentication for now?" prompt. The prompt added a step without meaningful choice — the unauthenticated path can't pull keys either way. Now the flow just follows auth state: signed in → authenticated flow + env pull; not signed in → keyless automatically (the keyless info message already points users to clerk auth login for later).
  • Keep clerk init --starter interactive without --framework. Running --starter without -y no longer errors with "Non-interactive mode requires --framework" — it only implies "yes, bootstrap," not "skip every prompt."

Also suppresses the "keyless not supported" framework message outside the bootstrap flow.

Test plan

  • bun run test — init suite covers the permutations (auth vs. not, API key vs. OAuth, bootstrap vs. existing repo, --starter with and without -y)
  • bun run lint / bun run typecheck
  • CI E2E suite passes (was failing on Astro / Next / TanStack / React Router before the API-key fix)
  • Manual: clerk init on a keyless framework while signed in → authenticated flow, no keyless prompt
  • Manual: clerk init on a keyless framework while signed out → keyless flow, no prompt
  • Manual: clerk init in an existing repo with keyless framework while signed in → no keyless prompt, env pulled
  • Manual: clerk init --starter (no -y) → interactive framework picker instead of an error

@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Apr 16, 2026

🦋 Changeset detected

Latest commit: 1682ce6

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

This PR includes changesets to release 1 package
Name Type
clerk 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

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 16, 2026

📝 Walkthrough

Walkthrough

The init command flow was changed to check authentication explicitly before skipping prompts. resolveKeylessMode now returns false when already authenticated and only enables keyless for unauthenticated, keyless-capable frameworks; it avoids logging “keyless not yet supported” unless bootstrap is requested. handleStarter and bootstrap calls now pass an implicitBootstrap flag instead of skipConfirm to bypass only the initial “create a new one?” confirmation. The exported askSkipAuth helper was removed and promptAndBootstrap gained an implicitBootstrap option. A new heuristics.isAuthenticated() helper was added (checks CLERK_PLATFORM_API_KEY or stored auth). Tests were updated to use isAuthenticated and to expand keyless/auth coverage.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description check ✅ Passed The pull request description clearly and comprehensively explains the changes, including four specific fixes to the clerk init command with concrete examples and a detailed test plan.
Title check ✅ Passed The title accurately summarizes the main changes: fixing authentication/keyless flow logic and resolving the --starter flag issue.

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


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@rafa-thayto
Copy link
Copy Markdown
Contributor Author

!snapshot

@github-actions
Copy link
Copy Markdown
Contributor

Snapshot published

npm install -g clerk@0.0.3-snapshot.v20260417120320
Package Version
clerk 0.0.3-snapshot.v20260417120320

Published from 5cf3c19

@rafa-thayto rafa-thayto force-pushed the rafa-thayto/more-init-fixes branch from 5cf3c19 to 7d45a72 Compare April 17, 2026 13:21
@rafa-thayto
Copy link
Copy Markdown
Contributor Author

!snapshot

@github-actions
Copy link
Copy Markdown
Contributor

Snapshot published

npm install -g clerk@0.0.3-snapshot.v20260417132423
Package Version
clerk 0.0.3-snapshot.v20260417132423

Published from 7d45a72

@rafa-thayto
Copy link
Copy Markdown
Contributor Author

!snapshot

@github-actions
Copy link
Copy Markdown
Contributor

Snapshot published

npm install -g clerk@0.0.3-snapshot.v20260417160442
Package Version
clerk 0.0.3-snapshot.v20260417160442

Published from 9a70430

@rafa-thayto rafa-thayto requested a review from wyattjoh April 17, 2026 16:39
Skip the askSkipAuth prompt and keyless flow when the user is already
authenticated, and suppress the "keyless not supported" message outside
of the bootstrap flow.
`handleStarter` forced `skipConfirm: true` when calling the bootstrap
flow, which conflated "user already opted into bootstrapping" with
"non-interactive mode" inside `promptAndBootstrap` and caused
`clerk init --starter` (without `-y`) to fail the framework guard with:
"Non-interactive mode requires --framework for new projects".

Add a separate `implicitBootstrap` override that only skips the initial
"create a new one?" confirm, leaving `skipConfirm` to mean non-interactive.
Previously, resolveKeylessMode and the skipAuth check only consulted
getAuthenticatedEmail (OAuth). When CLERK_PLATFORM_API_KEY was set
(as in CI E2E), the user was treated as unauthenticated, so
`clerk init --yes` on a keyless-supporting framework fell through
to keyless mode instead of pulling the real keys — breaking every
E2E fixture.

Introduce an isAuthenticated helper that returns true for either
auth mechanism, and use it in both branches.
Previously, an unauthenticated user on a keyless-capable framework
was asked "Skip authentication for now?" with a default of yes.
The prompt added a step without meaningful choice in practice —
the unauthenticated path can't pull keys regardless, and the
keyless info message already points users to `clerk auth login`
for later.

Now the flow just follows auth state: signed in → authenticated
flow + env pull; not signed in → keyless. Removes `askSkipAuth`
entirely.
@rafa-thayto rafa-thayto force-pushed the rafa-thayto/more-init-fixes branch from 9a70430 to 1682ce6 Compare April 17, 2026 16:54
@rafa-thayto rafa-thayto changed the title fix(init): check auth before keyless/skip-auth prompts fix(init): simplify auth/keyless flow and fix --starter Apr 17, 2026
Copy link
Copy Markdown
Contributor

@wyattjoh wyattjoh left a comment

Choose a reason for hiding this comment

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

Code Review — PR #175

Reviewed with Opus + Codex second-opinion validation.

Major

M1. Removing the bootstrap != null guard broadens keyless auto-select to existing projects (codex partial)
packages/cli-core/src/commands/init/index.ts:215-225 now returns keyless = true for any unauthenticated user on a keyless-capable framework, not only during bootstrap. Downstream effects:

  1. authenticateAndLink is skipped when users re-run clerk init signed out on an existing Clerk project.
  2. ctx.keyless = true at frameworks/helpers.ts:204-221,461-467 toggles permissive clerkMiddleware() (no route protection). Idempotency via hasClerkImport should prevent overwrites, but a scaffold-idempotency test for existingClerk: true + keyless: true would make the invariant load-bearing rather than incidental.
  3. env pull is skipped for the keyless branch.

The changeset does note keyless auto-select behavior, but the existing-project qualifier is not spelled out. Consider either restoring the if (!bootstrap) return false guard, or explicitly documenting the existing-project case in README and changeset.

M2. isAuthenticated() conflates "no credentials" with "network/API failure" (codex partial)
packages/cli-core/src/commands/init/heuristics.ts:139-147 delegates to getAuthenticatedEmail() which catches all errors and returns null. Expired tokens, Clerk 5xx, or offline laptops all silently demote the user into keyless (for keyless-capable frameworks) or skip-auth. Previously askSkipAuth gave the user a decision point. Consider a lighter credential-presence check (getToken() + CLERK_PLATFORM_API_KEY) for flow selection, reserving getAuthenticatedEmail() for the display label.

Minor

  • M3. isAuthenticated() is called twice on the authenticated + keyless-capable path (index.ts:90,94); resolve once and pass the boolean.
  • M4. packages/cli-core/src/commands/init/README.md:48-52 still documents the removed "Continue with temporary keys" prompt. Per .claude/rules/commands.md, the README must match behavior.
  • M5. New test "--starter without -y runs bootstrap interactively..." (index.test.ts:424-436) fully mocks promptAndBootstrap and never exercises the real guard at bootstrap.ts:173-177 that was the actual bug. Add a direct test for the guard.

Missed on first pass (codex caught)

  • Second README inconsistency. init/README.md:86 says non-keyless frameworks "always force authentication even with --yes", but index.ts:93-99 skips auth for unauthenticated users when -y is set.

Nits

  • isAuthenticated docstring (heuristics.ts:139-143) still references prompts that no longer exist.
  • BootstrapOverrides.implicitBootstrap doc (bootstrap.ts:135-140) doesn't note that skipConfirm supersedes it.
  • handleStarter (index.ts:153-163) dropping skipConfirm: true changes interactive --starter from previewPlan() to previewAndConfirm(). The changeset mentions --starter is "fully interactive", so this looks intentional; worth a bullet for reviewer transparency.

Positives

implicitBootstrap cleanly expresses "user opted into bootstrapping but did not opt out of prompts", better than overloading skipConfirm. Test additions cover the authentication x keyless x bootstrap/existing matrix well. isAuthenticated correctly short-circuits on CLERK_PLATFORM_API_KEY before network calls.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants