feat: zerion login and logout commands (PKCE browser flow)#17
Open
graysonhyc wants to merge 13 commits intomainfrom
Open
feat: zerion login and logout commands (PKCE browser flow)#17graysonhyc wants to merge 13 commits intomainfrom
graysonhyc wants to merge 13 commits intomainfrom
Conversation
Adds a PKCE-based browser login flow so users no longer have to paste
an API key from the dashboard. `zerion login --browser` opens the
dashboard, polls a backend status endpoint with the code_verifier,
and auto-saves the returned key. Also supports `--api-key` for direct
save and an interactive default. `zerion logout` clears the saved key
and any agent tokens without touching other config.
- cli/lib/auth/{pkce,browser-flow}.js: PKCE primitives + polling loop
- cli/commands/{login,logout}.js: new commands, registered in zerion.js
- cli/lib/util/constants.js: WEB_URL and CLI_STATUS_URL (env-overridable)
- tests/auth/{pkce,browser-flow}.test.mjs: unit tests incl. fixture hash
and mocked fetch polling (202 -> 200 and 401 rejection paths)
- package.json: adds `open` dep; test glob now includes subdirs
- README: new Quickstart Authentication section
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Show banner, welcome menu, masked key + config path on login success - Clear agentTokens on logout via unsetConfigValue and show config path - Add resolveX402(flags) helper; use across analytics commands - Remove @x402/svm dep; x402 now EVM/Base only - README: collapse x402 docs to single WALLET_PRIVATE_KEY example Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Prior commit (d45e339) mixed x402 simplification into a login-focused PR. Revert those x402/analytics/package changes and keep scope on login UX. Also address real edge cases in login/logout: - Accept real dashboard key prefixes. Validator required 'zk-' but dashboard issues 'zk_dev_…' / 'zk_prod_…'. Now accepts 'zk_' or 'zk-'. - Mask API key input on manual-paste path (readSecret mask=true) so the key no longer echoes to the terminal scrollback. - Guard interactive login against non-TTY stdin. CI/pipes now fail with 'no_tty' pointing at --browser / --api-key / ZERION_API_KEY instead of hanging forever on readline. - Warn on login flag collision (--api-key alongside --browser). - logout surfaces a lingering ZERION_API_KEY env var so users aren't silently still authed via the shell environment. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
# Conflicts: # package-lock.json # package.json
… tabs The real `open()` call was fire-and-forget, but on macOS `open https://mock.invalid` succeeds and opens a blank tab anyway — running `npm test` left several stale tabs in the user's browser. Accept an `opener` argument (defaults to the `open` package) and pass a no-op in tests. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Wallet setup shouldn't end at a just-created vault — the CLI is useless without an API key. After `wallet create` and `wallet import` succeed, if `getApiKey()` returns nothing, prompt the user to run `zerion login` right there. Accepting opens the browser-based PKCE flow and auto-saves the key; declining leaves a hint pointing at `zerion login` / ZERION_API_KEY and continues to the agent-token offer. - cli/lib/wallet/offer-login.js — new helper, skips silently when an API key already exists (config or env var), and in non-TTY contexts leaves a stderr note instead of blocking on readline. - wallet create / import — call offerLogin() before offerAgentToken so the user lands in a usable state by the end of setup. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The banner ("zerion cli vX.Y.Z / Wallet analysis & autonomous trading…")
is useful on standalone `zerion login`, but noisy when `wallet create`
or `wallet import` chain into login after the wallet output.
Add a `quiet` flag to loginCmd that skips banner() on both the browser
and interactive paths, and pass it from offerLogin().
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
When offerLogin() runs inside `wallet create`/`wallet import` and the user times out (5 min) or denies in the browser, loginCmd was calling process.exit(1). The wallet was already saved to disk but the outer flow — including the agent-token offer — died with a non-zero exit. Pass `quiet: true` through to runBrowser(); on failure it rethrows instead of exiting. offerLogin() now catches, prints a short skip notice pointing at `zerion login`, and continues to agent-token setup. Top-level `zerion login` behavior is unchanged (still exits non-zero on failure). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
# Conflicts: # README.md # cli/README.md # cli/commands/wallet/create.js # cli/commands/wallet/import.js # cli/utils/wallet/offer-login.js # cli/zerion.js # package-lock.json
# Conflicts: # package-lock.json
npm ci requires utf-8-validate@5.0.10 entry that prior --ignore-scripts install had skipped. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
zerion init now calls browserLogin() instead of prompting the user to paste an API key. The browser flow opens dashboard.zerion.io with a PKCE challenge and auto-saves the key once the user clicks Authorize. README and the zerion base skill lead with `zerion login` / `zerion logout`; copy-paste guidance is demoted to the non-interactive fallback (`--api-key` / `ZERION_API_KEY`) for CI and scripts. Drops the now-redundant `--browser` flag from `init` (browser is the only interactive path) and the local openBrowser() / readSecret() helpers. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds
zerion login/zerion logoutand routeszerion initthrough the new browser PKCE flow — users no longer have to copy an API key from the dashboard by hand.login(default) — opensdashboard.zerion.io/cli-authwith a PKCEcode_challenge, polls a backend status endpoint, and auto-saves the returned API key. Interactive picker offers browser-PKCE or paste-a-key.login --api-key <key>— non-interactive save (for scripts / CI).logout— clears savedapiKeyand anyagentTokens, warns ifZERION_API_KEYis still set in the shell.init— now usesbrowserLogin()directly instead of prompting for a paste.--browserflag dropped (browser is the only interactive path);--yesskips auth and points users atzerion loginfor later.wallet create/wallet import, if no API key is configured, the CLI offers to runlogininline. Failures don't kill the wallet flow.What's in the PR
cli/utils/auth/pkce.js— session ID (32B hex), verifier (32B base64url), SHA-256 challenge.cli/utils/auth/browser-flow.js— opensWEB_URL/cli-auth?code_challenge=…#session_id=…, pollsCLI_STATUS_URLevery 2s (5-min timeout).202= pending,401= rejected,200 { apiKey }= done. Accepts anopenerfor tests.cli/commands/login.js— banner, welcome menu, success block with team/API/masked key/config path. Reusable from inline flows viaquiet: true(rethrows instead ofprocess.exit).cli/commands/logout.js— single-path cleanup viaunsetConfigValue, env-var hint.cli/commands/init.js— now callsbrowserLogin(); dropped localopenBrowser()/readSecret()paste path and--browserflag.cli/utils/wallet/offer-login.js— post-wallet-setup login offer; suppresses banner on chained inline flows; survives login failure so wallet setup still completes.cli/commands/wallet/create.js,cli/commands/wallet/import.js— wired into the offer.cli/utils/common/constants.js—WEB_URLandCLI_STATUS_URL, both env-overridable for staging/tests.cli/router.js,cli/zerion.js— help output + command registration.README.md— new auth section leading withzerion login; copy-paste flow demoted to the non-interactive fallback (--api-key/ZERION_API_KEY). Setup table now listslogin/logout. Quickstart simplified tonpx -y zerion-cli init(no--browser).skills/zerion/SKILL.md— auth section now leads withzerion login/logout; env-var path is the non-interactive fallback for CI/headless agents.package.json— addsopendependency.package-lock.json— regenerated with optional deps sonpm ciis happy in CI.tests/auth/{pkce,browser-flow}.test.mjs— PKCE fixture hash + mocked polling (202→200 and 401 rejection paths). Browser flow accepts injected opener so tests don't launch real browser tabs.Edge cases handled
zk_…(real dashboard format, e.g.zk_dev_…/zk_prod_…) and legacyzk-…. Previously rejected valid keys.loginandinitdetect!process.stdin.isTTYand surface a structured error/skip pointing at--api-key/ZERION_API_KEYinstead of hanging on readline.readSecret({mask: true})so the API key no longer echoes into terminal scrollback.--api-keyalongside--browserprints a note that--api-keywins.logoutprints a hint tounset ZERION_API_KEYwhen the env var is still set, since it overrides the saved config.--forceis passed.loginis invoked from withinwallet create/import, a failed PKCE flow (timeout, network) does not abort wallet setup; the outer flow continues and the user can retry login later.browserLogin()accepts anopenerarg, so unit tests don't spawn real browser tabs in CI.Out of scope
No changes to x402, MPP, Solana support, analytics commands,
auth.js,client.js, or any other existing code paths. This PR only adds the login/logout surface, routesinitthrough it, and updates docs.Test plan
npm test— 101 unit tests pass, 0 failnpm cisucceeds locally (lockfile in sync; CI green)zerion logininteractive picker (option 1 → browser PKCE, option 2 → masked paste)zerion login --api-key zk_dev_…non-interactivezerion loginon already-logged-in config → exits cleanly, suggests--forcezerion init(no flags) → routes through browser PKCEzerion init -y→ skips auth withnon_interactivereasonzerion initwithZERION_API_KEYset → already-authenticated pathzerion logoutwith and withoutZERION_API_KEYset in shellzerion wallet create/importwith no API key → offers inline login; failure doesn't abort wallet setup/api/cli/statusendpoint)🤖 Generated with Claude Code