Skip to content

feat: default coder.useKeyring to true and harden shared credential handling - #1107

Merged
EhabY merged 5 commits into
mainfrom
feat/keyring-default-on
Sep 14, 2026
Merged

EhabY merged 5 commits into
mainfrom
feat/keyring-default-on

Conversation

@EhabY

@EhabY EhabY commented Sep 10, 2026

Copy link
Copy Markdown
Collaborator

Closes #1106.

What changes

  • coder.useKeyring defaults to true. On macOS and Windows with Coder CLI 2.29+, the session token also goes to the OS keyring through the CLI, so the terminal coder shares the session. Linux and older CLIs keep using a file. The extension's own secret storage is unchanged.
  • Every CLI 2.29+ call passes --use-keyring=<bool>, so the setting wins over CODER_USE_KEYRING. CODER_CONFIG_DIR is honored like --global-config.
  • The CLI store is either the CLI's own (cli: its config directory or the keyring, or a user directory from --global-config or CODER_CONFIG_DIR) or the extension's (extension: a file in the extension's per-deployment directory). CliAuth carries the choice and the flags follow from it.
  • Logout asks "Sign out of the Coder CLI too?" when the CLI holds the same token as the extension (checked with coder login token on 2.32+; older CLIs cannot be read, so the CLI's own store always asks). A CLI signed in with a different token is left alone. The extension's own store is always logged out, since coder logout revokes the token. OAuth sessions skip the prompt because logout revokes their token anyway. Manage Stored Credentials asks the same for one deployment and signs the CLI out on Remove All where the token matches.
  • Adopting the CLI's session for a different user than before asks first, reusing the link sign-in modal.
  • Without a downloaded binary, credential operations are skipped with one info line instead of failing; connect downloads the binary and stores the token.
  • --allow-redirects is passed to CLI 2.38+, whose coder login and coder logout otherwise fail for a deployment URL that redirects (fix: error on CLI HTTP redirects instead of following them coder#29104). The extension already follows redirects.
  • coder version is cached per binary until the file changes, and CLI reads or token checks are skipped when settings rule out the CLI's own store.
  • CLI token reads require 2.32, where file mode checks the stored URL against --url. The keyring path keys entries by host only and cannot be checked from the extension; bug: keyring session store keys entries by host, so http and https deployments share a token coder#29290 tracks the CLI fix.
  • A failed credential store shows the CLI's error with Open Settings. A logout that cannot remove every credential shows Show Output.

Flags per situation

Keyring User directory CLI Store Flags the extension adds
any any < 2.29 extension --global-config <ext dir> --url <url>
on any ≥ 2.29 cli --url <url> --use-keyring=true
off no ≥ 2.29 extension --global-config <ext dir> --url <url> --use-keyring=false
off yes 2.29 to 2.31 extension --global-config <ext dir> --url <url> --use-keyring=false
off yes ≥ 2.32 cli --url <url> --use-keyring=false

"Off" includes Linux. The extension's store drops the user's own --global-config item; the CLI's store keeps it. CLI 2.38+ also gets --allow-redirects.

Trade-offs

  • Signing in updates the CLI's session for that deployment, and signing out asks whether to sign the CLI out too. This is the behavior behind the earlier rollback (chore: revert keyring behavior #828), now documented in the setting and left to the user at logout.
  • A locked keyring fails the connection with an error instead of falling back to a file. The opt-out is coder.useKeyring: false.
  • Telemetry: the keyring_token login method folds into cli_token; credential spans carry store (cli, extension) and outcome (stored, logged_out, kept, no_binary); auth.logout gains user_dismissed.

Testing

pnpm test, pnpm typecheck, pnpm lint, and pnpm format pass. Developed on Linux; not yet verified on a keyring-capable machine: the shared token showing up in coder login token, CODER_CONFIG_DIR pass-through, and the locked-keychain error.

🤖 Generated with Claude Code

@EhabY
EhabY force-pushed the feat/keyring-default-on branch 2 times, most recently from 7128c90 to d38afa2 Compare September 10, 2026 17:00
@EhabY
EhabY marked this pull request as ready for review September 10, 2026 17:08
@EhabY
EhabY force-pushed the feat/keyring-default-on branch 2 times, most recently from 7b0efe7 to 5000734 Compare September 10, 2026 17:26
@matifali
matifali requested a review from code-asher September 10, 2026 17:38

@code-asher code-asher left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Looks good to me. I think maybe we should change whether we also log out the cli, but not blocking imo.

tbh I have not actually tested the keyring, being on Linux and all, but might find some time to run a VM later.

Comment thread src/core/cliCredentialManager.ts
Comment thread src/core/cliCredentialManager.ts Outdated
Comment thread src/core/cliCredentialManager.ts Outdated
Comment thread src/login/loginCoordinator.ts Outdated
Comment thread src/core/cliCredentialManager.ts
Comment thread src/core/cliCredentialManager.ts Outdated
Comment thread src/settings/cli.ts
Comment thread CHANGELOG.md Outdated
…andling

Store session tokens in the OS keyring by default on macOS and Windows,
passing --use-keyring explicitly to CLI 2.29 and later. Model the CLI
store as shared (the CLI's own directory, or a user directory on 2.31+)
or private (a file in the extension's per-deployment directory), and
treat CODER_CONFIG_DIR like a user --global-config.

Record who minted each stored token so logout runs coder logout against
a shared store only for a token the extension created and the CLI still
holds. Ask before adopting the CLI's session for a different user. Show
an error with Open Settings when the CLI cannot store the token at
login, and a Show Output button when logout cannot remove every
credential.

Closes #1106
The CLI keys keyring entries by host without the scheme, so an http
lookup returns the https deployment's token. File reads are left to the
CLI, whose file mode checks the stored URL against --url from 2.32.
@EhabY
EhabY force-pushed the feat/keyring-default-on branch 5 times, most recently from 9f948ab to 59444ea Compare September 14, 2026 15:58
…g out the CLI

A missing CLI binary is no longer an error for credential operations.
Storing and reading at login, and logging out, skip the CLI with an info
log, since connecting downloads the binary and stores the token again.
Only a binary that exists but cannot be resolved still reports an error.

Logout asks whether to sign out the CLI too when its own store holds the
same token as the extension, read with `coder login token` on 2.32+
(older CLIs cannot be read, so the CLI's store always asks). A CLI signed
in with a different token is left alone. This drops the `tokenSource`
field and the stored provenance it fed. The extension's own store is
always logged out, since `coder logout` revokes the token. OAuth
sessions skip the prompt because logout revokes their token anyway.
Manage Stored Credentials asks the same question for one deployment and
signs the CLI out for Remove All wherever it holds the same token.

`CliAuth.store` is now `cli` or `extension` instead of `shared` or
`private`, naming whose store it is.

The http keyring guard is removed. The CLI keys entries by host and
`coder login token` prints only the token, so the extension cannot check
the scheme; coder/coder#29290 tracks verifying `--url` in the CLI.

The credential spans record an `outcome` so skipped and kept operations
are distinguishable from ones that ran the CLI. The store-failure error
now shows the CLI's stderr instead of a generic wrapper message.
coder/coder#29104 makes the CLI return an error on an HTTP redirect
instead of following it. The extension follows redirects itself, so a
deployment URL that redirects kept working for the API but made `coder
login` fail at connect and `coder logout` fail at logout. The flag is
global, so `coder ssh` gets it too. Older CLIs followed redirects by
default and do not know the flag, so it is gated on the version.
@EhabY
EhabY force-pushed the feat/keyring-default-on branch from 59444ea to 91c65a2 Compare September 14, 2026 16:18
`coder version` is cached per binary while the file's mtime and size
match, so the credential operations, the binary check on connect, and
the CLI command flow stop spawning it for the same file.

Reads and token checks run only when the CLI is downloaded and settings
allow its own store, sparing Linux two process spawns per login and
logout. The token check before the logout prompt runs under the same
cancellable progress as the login read, so a locked keychain no longer
freezes Logout until the exec timeout, and the progress only appears
when a CLI call is made. Remove All logs hosts out one at a time, since
`coder logout` rewrites the whole keyring entry.
@EhabY
EhabY force-pushed the feat/keyring-default-on branch from 9ac4d3e to b880ac9 Compare September 14, 2026 16:45
@EhabY
EhabY merged commit fdabe5e into main Sep 14, 2026
12 of 13 checks passed
@EhabY
EhabY deleted the feat/keyring-default-on branch September 14, 2026 16:55
EhabY added a commit that referenced this pull request Sep 14, 2026
Group the workspaces view's "..." menu so Switch Deployment and Logout come first, with Network Check on its own. Bump the version to 1.16.3 and add the changelog section covering the keyring default and the --allow-redirects fix from #1107
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.

Default coder.useKeyring to true

2 participants