Skip to content

fix(install): configure sandbox application URLs across SDKs - #250

Merged
nicknisi merged 34 commits into
mainfrom
fix/installer-register-redirect-uris
Sep 25, 2026
Merged

nicknisi merged 34 commits into
mainfrom
fix/installer-register-redirect-uris

Conversation

@jasonbarry

@jasonbarry jasonbarry commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

Problem

The installer skipped callback and CORS registration for most SDKs. Expanding setup also exposed legacy paths that could write localhost settings with a production key, replace an existing homepage, mutate two different environments, or report success after callback registration failed.

Changes

  • Configure URLs after the agent through one target: the client-ID-matched sandbox dashboard application, or the sandbox API-key-only fallback. Non-Next.js SDKs include CORS in that choice; its origin follows the callback URL, including explicit custom origins.
  • Keep production environments read-only, preserve existing dashboard settings, and merge/recheck/read back list mutations. REST homepage writes require an explicit --homepage-url or a matching stored unclaimed environment.
  • Fail installation when the callback cannot be registered. Report incomplete additional settings honestly, including independently verified sign-out settings.
  • Add documented sign-in paths and generate the appropriate public login route for each SDK. Server SDKs configure Initiate login URI through the selected dashboard application when available.
  • For React and vanilla JS, generate /login and configure the explicit bundler-prefixed callback, but leave Initiate login URI unchanged until browser verification. Users should open /login while signed out, confirm automatic sign-in, and then set that URL in the dashboard.
  • Remove the client-route AST analyzer and direct Babel dependency. Static source patterns cannot prove that a route is mounted or starts sign-in. Prompts follow app conventions rather than parser-supported syntax. Bounded callback/env checks remain; incomplete scans warn instead of failing installation.
  • SvelteKit defaults to port 5173 and /callback, per its README.

Scope

Validation

  • bun install --frozen-lockfile
  • bun run typecheck
  • bun run test: 3,116 passed on the final full-suite run. An earlier run failed the untouched skills-repair sibling-protection test; it passed in isolation and on the full rerun without a code change.
  • bun run lint
  • bun run build
  • Independent review of the simplification and retained URL-safety boundaries.
  • Live sandbox installer/browser smoke for a React app and a server SDK app. Not run during this revision; local tests do not establish live authentication success.

Original implementation session: https://claude.ai/code/session_018EgeNr2FXXVcJ5o165U5Lx

@jasonbarry
jasonbarry changed the base branch from nicknisi/remove-tui to nicknisi/installer-tui September 24, 2026 23:40
@jasonbarry
jasonbarry marked this pull request as ready for review September 24, 2026 23:46
@greptile-apps

greptile-apps Bot commented Sep 24, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 5/5

[Medium risk] Adds sign-in route configuration to the SDK installer workflow.

The PR appears safe to merge based on this review; no new findings or outstanding previous findings remain.

Summary

The PR moves sandbox URL configuration after agent installation, selects a single WorkOS target, and adds SDK-specific sign-in guidance and bounded client callback checks.

  • It preserves existing dashboard settings where possible and reports callback, CORS, sign-out, and initiate-login status separately.
  • React and vanilla JS leave the Initiate login URI unchanged pending browser verification.
Diagram
%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[Prepare local environment] --> B[Agent installs integration]
  B --> C[Validate generated integration]
  C --> D{WorkOS URL target}
  D -->|Matched sandbox dashboard application| E[Merge and verify application URLs]
  D -->|Sandbox API key only| F[Register callback and CORS; conditionally set homepage]
  E --> G[Report verified and pending settings]
  F --> G
Loading

Reviews (20) · Last reviewed commit: "ci: rerun checks after retargeting insta..."

Comment thread src/lib/validation/validator.ts Outdated
Comment thread src/lib/validation/validator.ts Outdated
Comment thread src/lib/validation/validator.ts Outdated
Comment thread src/lib/validation/validator.ts Outdated
Comment thread src/lib/validation/validator.ts Outdated
@jasonbarry
jasonbarry requested a review from nicknisi September 25, 2026 00:14
Comment thread src/lib/validation/validator.ts Outdated
Comment thread src/lib/validation/validator.ts
Comment thread src/lib/validation/validator.ts Outdated
Comment thread src/lib/validation/validator.ts Outdated
Comment thread src/lib/validation/validator.ts Outdated
@nicknisi
nicknisi added this pull request to stack #248 September 25, 2026 00:45
Comment thread src/lib/validation/validator.ts Outdated
Comment thread src/lib/workos-management.ts
Comment thread src/lib/validation/validator.ts Outdated
Comment thread src/lib/validation/validator.ts Outdated
Comment thread src/lib/validation/validator.ts Outdated
Comment thread src/lib/validation/client-sign-in.ts Outdated
Comment thread src/lib/run-with-core.ts Outdated
Comment thread src/lib/validation/client-sign-in.ts Outdated
Comment thread src/lib/run-with-core.ts Outdated
@nicknisi nicknisi changed the title fix(install): save redirect, sign-out and initiate login URIs for every SDK fix(install): configure sandbox application URLs across SDKs Sep 25, 2026
@nicknisi
nicknisi force-pushed the nicknisi/installer-tui branch from d201fd5 to 5737030 Compare September 25, 2026 10:00
@nicknisi
nicknisi force-pushed the fix/installer-register-redirect-uris branch from c8a19c5 to 10f7fe9 Compare September 25, 2026 10:00
jasonbarry and others added 8 commits September 25, 2026 05:09
The installer machine only called autoConfigureWorkOSEnvironment for
TanStack Start and React Router, and returned early for non-JavaScript
SDKs. Each integration's run() skips its own call when the machine passes
credentials, so SvelteKit, Node, PHP, Laravel, Python, Ruby, Go, .NET,
Kotlin and Elixir never registered their redirect URI, CORS origin or
homepage URL.

Key the check on the integration's requiresApiKey flag (Next.js keeps its
post-validation path), and register URLs before the non-JavaScript return.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018EgeNr2FXXVcJ5o165U5Lx
… SDKs

React and vanilla JS (Vite) apps declare requiresApiKey: false, so the
previous fix still skipped them, though the install usually holds an API
key from the staging credentials. A client-only app needs its callback and,
above all, its CORS origin registered. Register URLs for every SDK except
Next.js whenever an API key is available.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018EgeNr2FXXVcJ5o165U5Lx
Only Next.js set the Sign-out URI and Initiate login URI, through the
dashboard GraphQL path. The REST API has no endpoint for either, so other
SDKs left both for the user to set by hand.

- Run configureAuthkitApplication after the agent for every SDK. For SDKs
  other than Next.js, a failure leaves the settings for the dashboard
  instead of failing a finished install.
- Save the origin as the Sign-out URI everywhere. Save an Initiate login
  URI only where the SDK guide fixes the route (signInPath in
  cli.config.ts); otherwise report it as not set.
- React and vanilla JS apps get a /sign-in client route that calls
  signIn() on load, checked by validation before it is saved.
- Pin the agent to that exact route in the prompt.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018EgeNr2FXXVcJ5o165U5Lx
Checked the saved Initiate login and callback paths against the WorkOS
docs and SDK READMEs.

- React and vanilla JS use /login, as the authkit-react docs do, and must
  pass WORKOS_REDIRECT_URI as redirectUri: the SDK defaults to the page
  origin, which the installer never registers. Validation checks both.
- Save the documented sign-in routes for React Router (/login), TanStack
  Start (/api/auth/sign-in), SvelteKit (/sign-in), Node (/login, which also
  fixes its outro copy) and plain PHP (/login.php).
- SvelteKit defaults to Vite's 5173 and /callback, per its README.
- Pin the route in the custom Ruby, Go, .NET and Elixir prompts too, so
  the agent cannot fall back to a path the dashboard does not point at.
- Drop the query-parameter pass-through: AuthKit keeps password-reset and
  invitation details through the redirect.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018EgeNr2FXXVcJ5o165U5Lx
- Build the default redirect URI in one resolveRedirectUri() helper.
- Derive client-only SDKs from requiresApiKey instead of a second list.
- Scan client source once, in parallel, for both the sign-in route and
  redirectUri; check only that route after the agent instead of rerunning
  the full validator.
- Report why an initiate login URI was skipped (no fixed route vs. a
  missing route) and show an unusable callback URL in the checklist.
- Give the Python prompt the pinned sign-in route like the other SDKs.
- Read the Node outro routes from config.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018EgeNr2FXXVcJ5o165U5Lx
Address review feedback on the client-only validation:

- A link to /login no longer counts as the route. Require a route
  declaration (router path, createFileRoute, or a pathname check) or a
  static page that calls signIn().
- Check that the prefixed env var the client reads as redirectUri (for
  example VITE_WORKOS_REDIRECT_URI) is set, and flag an unprefixed one
  the build tool never exposes. The installer writes only the unprefixed
  WORKOS_REDIRECT_URI.
- Read source files in bounded batches instead of all at once.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018EgeNr2FXXVcJ5o165U5Lx
For client-only apps, the installer now writes VITE_ (or REACT_APP_ for
Create React App) WORKOS_CLIENT_ID and WORKOS_REDIRECT_URI itself, instead
of asking the agent to copy them and validating the copy. The validator
only checks that the client reads the variable the installer wrote.

Also share one route check between validation and the save step, build
the route pattern from a named list, and read static pages in parallel.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018EgeNr2FXXVcJ5o165U5Lx
A Vite app may read the unprefixed WORKOS_REDIRECT_URI in server-side
files such as vite.config.ts. Check Vite browser code through
import.meta.env, and Create React App through process.env in src/, so
those files no longer fail validation.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018EgeNr2FXXVcJ5o165U5Lx
jasonbarry and others added 21 commits September 25, 2026 05:09
Use one fast-glob call whose root depends on the bundler, look up the
bundler prefix once per validation, and add an envReadIssue spec helper.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018EgeNr2FXXVcJ5o165U5Lx
Server code in a nested folder such as src/server/ may read the
unprefixed redirect URI. Exclude server files and folders at any depth;
bundler config and scripts stay root-only so browser files in src/ are
still checked.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018EgeNr2FXXVcJ5o165U5Lx
…rver paths

Every server-path exclusion existed to hide one read: Node code reading
process.env.WORKOS_REDIRECT_URI. Exempt that read for Vite, where the
same read in browser code throws at page load (no process global), and
drop the server/ and scripts/ exclusions. Create React App keeps flagging
it, because CRA defines process.env in the browser and the read comes
back undefined without an error. The silent cases (import.meta.env with
the wrong name, process.env with a browser prefix) are still flagged in
any file.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018EgeNr2FXXVcJ5o165U5Lx
The route check only recognised `pathname === '/login'`. The agent
followed the prompt and wrote `const path = window.location.pathname;
if (path === '/login')`, which failed validation in a real Vite app.
Accept a comparison against any identifier, in either order.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018EgeNr2FXXVcJ5o165U5Lx
The agent prompt and the route check had no shared contract, so the
agent could write a form the validator did not know. The prompt now names
the forms the validator accepts, and the route regex uses String.raw
like its declarations.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018EgeNr2FXXVcJ5o165U5Lx
The API-key setup step registers a localhost redirect URI and CORS origin
and sets the homepage URL. It ran for any key, and a production key can
reach the installer three ways: the --api-key flag or WORKOS_API_KEY, the
project's env file, or an active profile of type production (the
environment picker lists every profile with a key). With this PR running
the step for every SDK, a Go, Rails, or Django install with a live key
would add localhost URLs to production and replace its homepage.

autoConfigureWorkOSEnvironment now does nothing unless the key starts with
sk_test_, and reports the redirect URI and CORS origin as skipped with the
reason, so the checklist and summary show them. The check sits in the
function, not a caller, because the installer machine, agent-runner, and
some integrations' own run() all reach it. It is the same sk_test_ test
the Next.js API-key path already uses, so every write path now agrees.
…overwritten

The API-key setup step wrote the homepage URL on every sandbox. The
homepage is one value per environment, and the REST API can set it but not
read it (its GET answers 404), so the write replaced whatever a teammate
had set on a shared sandbox.

It now follows the rule #249 set for the Next.js API-key path: write it only
when the user asked for it (--homepage-url) or the key belongs to the
stored unclaimed environment, whose dashboard nobody has had. Otherwise the
Homepage URL row says it wasn't changed. With a login, the later dashboard
step reads the current homepage and fills an empty one.
The client-only checks scanned every source file in a Vite project, so they
could not tell browser code from a server or script beside it. Each fix moved
the gap: a /login route in server.js counted as the client route, and
exempting server reads hid browser code that read
process.env.WORKOS_REDIRECT_URI, which Vite leaves undefined. The route check
also counted any `x === '/login'` comparison as a route.

The scan now traces what the browser loads: every HTML page and its script
srcs (Vite's index.html, a plain app's pages), or Create React App's
src/index, then their relative, root and @/ imports. A server, a script or
the bundler config is never reached from there, wherever it lives, so traced
browser code that reads the unprefixed var is flagged again. A project with
no entry keeps the old whole-project scan and its exemption.

A comparison counts as the route only when it checks the pathname:
`location.pathname === '/login'`, a variable read from it, or
`case '/login':` in a switch on it. `path = '/login'` (an assignment) no
longer passes as `path="/login"`. These are the forms the agent prompt names.
Revert df2d1f4. The scanner introduced false negatives for inline module imports and custom aliases without reliably proving that a route starts sign-in. Restore the previous validator and leave those review findings open. Keep the production-key guard and homepage protection unchanged.
When authenticated command smoke fails, issue a single GET /connections using the same smoke credential and configured API host through curl instead of the compiled CLI. Discard the body, do not follow redirects, and log only HTTP status, curl exit status, and the request ID. Keep the original failed check red.
Check conventional client roots without an import resolver, excluding server, API, function, script and other workspace paths. Flag Node env reads in Vite client code rather than globally exempting them. Restrict route evidence to supported router forms or actual pathname comparisons and require a sign-in call. Limit reads to 256 files, 256 KiB per file and 4 MiB total; incomplete scans cannot authorize saving a sign-in destination. Add regression cases for the review findings and previously broken inline/custom-alias layouts.
Use the established explicit-or-unclaimed homepage policy in the API-only fallback too. Authorized writes no longer require the unsupported homepage GET to succeed; unknown existing values remain untouched with an honest reason. A missing initiate-login destination leaves setup unverified even when other writes succeed. Add real GET-404 and missing-route regression coverage.
Fail required validation when bounded scans are incomplete. Replace disconnected route/signIn string matches with parsed startup or React mount-effect branches: the matching positive pathname branch must directly call signIn. Ignore comments, strings, click callbacks and unrelated routes. Standardize this conservative source-evidence form in the client prompt; no import graph or bundler resolution. Promote the already-locked Babel parser to a direct dependency and add regression coverage.
Preflight live smoke with one direct read-only API request. Missing credentials or direct HTTP401 report live checks NOT RUN with an explicit warning/summary instead of misclassifying a CLI regression. HTTP200 enables the unchanged authenticated CLI checks, whose failures still fail CI. All other HTTP or transport failures remain fatal. Localhost-only tests cover status handling, non-disclosure, no redirects, and propagation of CLI failures.
Tie JSX and object-route targets to their lexical component definitions and mount effects, including relative default/named exports from the bounded source set. A routed component does not need a redundant pathname guard. Reject unrelated, shadowed, reassigned, click-only and unresolved component bindings. Preserve the bounded scan and existing guarded startup path; no disk-expanding import traversal.
Defer non-Next.js URL writes until post-agent setup chooses the client-ID-matched dashboard application or the API-key-only fallback. Never write early through API key A then later through dashboard environment B. Include CORS in that choice: preserve existing dashboard origins with dry-run/recheck/readback, or add through REST only on the API-key path. An unregistered callback cannot be reported as successful setup. Cover mismatched credentials, late sessions, production refusal, CORS preservation and incomplete results.
Remove the client-route AST analyzer and its direct Babel dependency. Keep generating a public login route using app conventions, but leave the client-only Initiate login URI unchanged until browser verification. Treat scan limits as warnings while preserving callback/env checks and mandatory registration.\n\nRetain sandbox/homepage protections and single-target writes. Derive CORS from the callback origin and report read-back sign-out independently of pending login verification. CI smoke changes are split onto ci/smoke-auth-preflight.
@nicknisi
nicknisi force-pushed the fix/installer-register-redirect-uris branch from 10f7fe9 to efe729e Compare September 25, 2026 10:09
@nicknisi
nicknisi removed this pull request from stack #248 September 25, 2026 10:10
@nicknisi
nicknisi changed the base branch from nicknisi/installer-tui to main September 25, 2026 10:10
@nicknisi
nicknisi merged commit 586b2fa into main Sep 25, 2026
5 checks passed
@nicknisi
nicknisi deleted the fix/installer-register-redirect-uris branch September 25, 2026 10:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants