Skip to content

CLI: log in to several Convex accounts and pick one per directory - #576

Draft
judioo wants to merge 1 commit into
convex:mainfrom
judioo:cli-multiple-accounts
Draft

judioo wants to merge 1 commit into
convex:mainfrom
judioo:cli-multiple-accounts

Conversation

@judioo

@judioo judioo commented Sep 27, 2026

Copy link
Copy Markdown

Closes #326.

Problem

The CLI keeps one Convex login per machine in ~/.convex/config.json. Anyone whose projects belong to different Convex accounts (consultants, agencies, work and personal) has to logout and login whenever they switch projects, and can't run npx convex dev for two such projects at the same time.

The common workaround, putting CONVEX_DEPLOY_KEY in each project's .env.local, has sharp edges of its own:

  • npx convex login tests the deploy key instead of the account token, fails, and runs a new browser login on every call. Each run leaves another personal access token on the account.
  • A prod: key in .env.local makes npx convex dev --once and npx convex run act on production, with nothing in the output saying so.
  • A deploy key is scoped to one deployment, so dev and deploy in the same project need different keys.

What this adds

  • Several accounts per machine, one per directory. npx convex login --account adds an account without logging out of the others. Accounts are keyed by Convex member id, since an email can belong to more than one member. npx convex account use <member-id> binds a directory (and everything under it) to an account. Unbound directories use the default account.
  • npx convex account: list (with a live check of every token), use, unbind, default, describe, settings.
  • npx convex dev knows when a project belongs to another account. Instead of going straight to "create a new project", it explains which project .env.local points to and offers a saved account that can reach it, a login to another account, or setting up a different project. Only the last one rewrites CONVEX_DEPLOYMENT.
  • Checks before binding. Binding a directory first checks that the account can reach the directory's CONVEX_DEPLOYMENT.
  • Tidy tokens. A token saved by an older login is matched to its member by comparing personal access token lists, then filed under the member id. When a newer token replaces an older one for the same member, the older one is revoked. That can be turned off with npx convex account settings revoke-replaced-tokens false.

Existing behavior

Nothing changes for a machine with one login until npx convex login --account adds a second account: same config shape, same login and logout, same credentials for every command, nothing revoked. Deploy keys keep priority over accounts, so CI and existing projects behave as before.

The top-level accessToken keeps mirroring the default account, so a project pinned to an older CLI keeps working as that account. An older logout still deletes the whole file.

A few changes apply to everyone:

  • npx convex login checks the account token, not the deploy key, so it no longer logs in on every run when CONVEX_DEPLOY_KEY is set.
  • When a deploy key overrides the login, login, login status and account list show a banner, and other commands print a one-line WARNING:. Machines with only a deploy key (CI) see nothing new.
  • npx convex dev explains an inaccessible project as described above. With --team and --project it keeps the old flow.

npm-packages/convex/src/cli/README.md documents every behavior, prompt and non-interactive path.

API notes for reviewers

  • The member id comes from GET /api/dashboard/profile, called with the browser-login token right after the device flow. That endpoint doesn't accept personal access tokens, which is why older tokens are matched through GET /v1/list_personal_access_tokens. A public "current member" endpoint for personal access tokens would simplify this.
  • Also used: GET /v1/deployments/<name> (access check), POST /v1/delete_personal_access_token (revocation), GET /api/teams (default description).

Tests

  • src/cli/accounts.test.ts (47 tests) runs the built CLI against a fake Convex API on localhost, with a fresh home and project directory per test. It covers single-account behavior, deploy keys, login --account, old tokens, revocation, binding and access checks, account list, logout, and dev with a project another account owns.
  • src/cli/lib/utils/globalConfig.test.ts (16 tests) covers the config helpers.
  • The single-account tests also pass against the published convex@1.46.0 (set CONVEX_CLI_UNDER_TEST to its bin/main.js). The login-loop test fails on 1.46.0 and passes here.
  • Interactive prompts (account picker, "Use it anyway?", "Replace it?") were tested by hand against two real accounts.

npm test, npm run typecheck and eslint src/cli pass.

Keep several Convex accounts logged in on one machine and bind project
directories to them, so projects owned by different accounts can be worked
on side by side (convex#326).

- `~/.convex/config.json` gains `accounts` keyed by Convex member id,
  `instances` binding directories to accounts, and `settings`. The top-level
  `accessToken` mirrors the default account so older CLI versions keep
  working. Nothing changes until `npx convex login --account` adds a second
  account.
- New `npx convex account` command: list (with live token checks), use,
  unbind, default, describe, settings. `login --account [member-id]`,
  `login --yes`, `logout --account` and `logout --all` are new options.
- `npx convex login` checks the account token instead of a deploy key, which
  stops it logging in again on every run when CONVEX_DEPLOY_KEY is set.
- A deploy key that overrides the login is called out in a banner on
  login/status/list and in a one-line warning on other commands, only when
  the machine also has a login.
- `npx convex dev` explains when the project in .env.local belongs to
  another account and offers to switch to or log in to that account before
  rewriting CONVEX_DEPLOYMENT.
- Tokens saved before member ids are identified by comparing personal access
  token lists, and replaced tokens are revoked unless
  `revoke-replaced-tokens` is turned off.
- Binding a directory checks that the account can reach its
  CONVEX_DEPLOYMENT.

See src/cli/README.md for the full behavior. Tests run the built CLI against
a fake Convex API; the single-account tests also pass against convex@1.46.0.
@ianmacartney

Copy link
Copy Markdown
Member

Very nice! I had started another implementation that uses named profiles (like "work" / "personal") but I really like the framing here, so I'm going to incorporate the two together and list you as a co-author. I'm thinking of putting the commands under npx convex profile instead of "account"

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.

Project level CLI login

2 participants