Skip to content

[WEBXP-469] Add circleci signup command with hybrid browser flow#1196

Open
Fab10-CircleCi wants to merge 1 commit intoCircleCI-Public:mainfrom
Fab10-CircleCi:fabioramirez/webxp-469-cli-hybrid-signup-fixes
Open

[WEBXP-469] Add circleci signup command with hybrid browser flow#1196
Fab10-CircleCi wants to merge 1 commit intoCircleCI-Public:mainfrom
Fab10-CircleCi:fabioramirez/webxp-469-cli-hybrid-signup-fixes

Conversation

@Fab10-CircleCi
Copy link
Copy Markdown

Checklist

=========

  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have checked for similar issues and haven't found anything relevant.
  • This is not a security issue (which should be reported here: https://circleci.com/security/)
  • I have read Contribution Guidelines.

Internal Checklist

  • I am requesting a review from my own team as well as the owning team
  • I have a plan in place for the monitoring of the changes that I am making (this can include new monitors, logs to be aware of, etc...)

Changes

=======

  • Add circleci signup command with hybrid browser flow for CLI authentication
  • Start ephemeral HTTP server on 127.0.0.1:0 with single /token endpoint
  • Open browser to app.circleci.com/authentication/login with return-to pointing to /successful-signup (relative path — no Auth0 config changes needed)
  • CORS middleware pinned to https://app.circleci.com with Access-Control-Allow-Private-Network: true for Chrome PNA
  • Frontend creates PAT via cookie-authenticated API call, then delivers token to CLI via cross-origin fetch() to http://127.0.0.1:PORT/token
  • State validation via cli_state param (namespaced to avoid Auth0 collision)
  • Error handling for PAT creation failures from frontend (error query param)
  • --no-browser flag for headless/SSH environments (prints URL, prompts for manual PAT paste)
  • --force flag to bypass already-authenticated guard
  • Already-authenticated guard: exits early if token exists in config
  • Telemetry event (cli-signup) and workflow step tracking
  • 17 unit tests covering CORS, token handling, state validation, error paths, auth guard
  • Update root_test.go subcommand count from 29 to 30

Rationale

=========

This implements the CLI side of the hybrid browser signup flow (WEBXP-469, follow-up from WEBXP-417). The goal is to let new users run circleci signup, complete signup in the browser, and have the CLI automatically authenticated — no manual token copy-paste required.

Based on Pete's feedback, the browser never navigates to localhost. Instead, the frontend page on app.circleci.com creates a PAT and delivers it directly to the CLI's local server via a cross-origin fetch(). The return-to is a relative path (/successful-signup?source=cli&cli_port=PORT&cli_state=STATE) so it passes the existing domain whitelist with zero backend/Auth0 changes.

Frontend counterpart: circleci/web-ui-consolidated#6482

Considerations

==============

  • Cross-origin fetch (HTTPS → localhost): Browsers treat localhost/127.0.0.1 as "potentially trustworthy" per the W3C spec, allowing HTTPS→HTTP fetches. Chrome additionally requires Access-Control-Allow-Private-Network: true (PNA header) which is included.
  • CORS origin pinned: The Access-Control-Allow-Origin header is set to exactly https://app.circleci.com — never *.
  • State parameter: Uses cli_state (not state) to avoid collision with Auth0's own state parameter in the redirect chain.
  • 5-minute timeout: Prevents the CLI from hanging indefinitely. All failure paths suggest circleci setup as fallback.
  • No new dependencies: Uses crypto/rand, net/http, net/url, pkg/browser — all already in the project.

🤖 Generated with Claude Code

Implements a signup command using Pete's cross-origin token delivery
approach. The browser stays on app.circleci.com the entire time —
the frontend creates a PAT and delivers it to the CLI's localhost
server via a cross-origin fetch().

- Ephemeral HTTP server on 127.0.0.1:0 with single /token endpoint
- CORS middleware pinned to https://app.circleci.com
- Access-Control-Allow-Private-Network header for Chrome PNA
- State validation via cli_state param (namespaced to avoid Auth0 collision)
- Error handling for PAT creation failures from frontend
- --no-browser fallback for headless/SSH environments
- --force flag to bypass already-authenticated guard
- Telemetry events and workflow step tracking
- 17 unit tests

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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.

1 participant