Problem
ensureTokenBackend() in cli/root.go forces the file-based backend whenever --global-config / CODER_CONFIG_DIR is set to anything other than config.DefaultDir(), regardless of --use-keyring:
assumeExtensionInUse := r.globalConfig != config.DefaultDir() && !r.useKeyringWithGlobalConfig
keyringSupported := runtime.GOOS == "windows" || runtime.GOOS == "darwin"
if r.useKeyring && !assumeExtensionInUse && keyringSupported {
...
}
This was introduced in #20943 as a compatibility shim after #20851 enabled keyring storage by default, since editor extensions invoke the CLI with --global-config and assumed the session token would be readable from disk. The code comment already flags it as temporary.
Two consequences today:
- Keyring and per-deployment config isolation are mutually exclusive. Any client that needs its own config directory (editor extensions, CI wrappers, multi-deployment setups) is forced back to a plaintext
session file on disk. There is no way to opt in.
- Clients cannot hold independent tokens for the same deployment. The keyring entry is a single JSON credentials map keyed only by normalized host, stored under the
coder-v2-credentials service name (cli/sessionstore/sessionstore.go). Any two clients pointing at the same deployment necessarily share one credential, so a logout in one revokes the session for the other.
Proposal
Allow --use-keyring to be honored when --global-config is set, and give callers a way to scope their credential so it does not collide with the shared default entry. Rough shape:
- Drop the
assumeExtensionInUse short-circuit and treat --use-keyring as authoritative. Keep file storage as the default when --global-config is set so existing callers are unaffected unless they explicitly opt in.
- Support a distinct keyring namespace per caller, either derived from the config directory or set explicitly (the existing
keyringServiceName field is test-only today, WithKeyringServiceName). Callers that want to share credentials with Coder Desktop keep using DefaultServiceName; callers that want isolation get their own.
Open questions
- Should the namespace be derived from the config directory path, or an explicit flag? A derived value is transparent to callers but makes the credential name depend on a filesystem path, which is awkward to document and to clean up.
- If a caller uses an isolated namespace, credential sharing with Coder Desktop and the JetBrains Toolbox plugin is lost for that caller. Is that acceptable as opt-in behavior?
- What should happen on
logout when both a default-namespace and an isolated credential exist for the same host?
- Linux still has no keyring implementation (
sessionstore_other.go returns ErrNotImplemented), so this stays macOS/Windows only.
Related
Created on behalf of @EhabY
Problem
ensureTokenBackend()incli/root.goforces the file-based backend whenever--global-config/CODER_CONFIG_DIRis set to anything other thanconfig.DefaultDir(), regardless of--use-keyring:This was introduced in #20943 as a compatibility shim after #20851 enabled keyring storage by default, since editor extensions invoke the CLI with
--global-configand assumed the session token would be readable from disk. The code comment already flags it as temporary.Two consequences today:
sessionfile on disk. There is no way to opt in.coder-v2-credentialsservice name (cli/sessionstore/sessionstore.go). Any two clients pointing at the same deployment necessarily share one credential, so a logout in one revokes the session for the other.Proposal
Allow
--use-keyringto be honored when--global-configis set, and give callers a way to scope their credential so it does not collide with the shared default entry. Rough shape:assumeExtensionInUseshort-circuit and treat--use-keyringas authoritative. Keep file storage as the default when--global-configis set so existing callers are unaffected unless they explicitly opt in.keyringServiceNamefield is test-only today,WithKeyringServiceName). Callers that want to share credentials with Coder Desktop keep usingDefaultServiceName; callers that want isolation get their own.Open questions
logoutwhen both a default-namespace and an isolated credential exist for the same host?sessionstore_other.goreturnsErrNotImplemented), so this stays macOS/Windows only.Related
--global-configshort-circuit this issue proposes to liftCreated on behalf of @EhabY