Skip to content

Keychain lookup ignores account field, breaks multi-account setups #12885

Description

@veeshpath

Description

When two GitHub accounts are configured for the same host (github.com) using GH_CONFIG_DIR to separate configs, gh auth token retrieves the wrong token because the keychain lookup doesn't include the account name.

Steps to reproduce

  1. Set up two gh configs for different GitHub accounts on the same host:
# Default config (~/.config/gh/)
gh auth login  # login as user-a

# Personal config (~/.config/gh-personal/)
GH_CONFIG_DIR=~/.config/gh-personal gh auth login  # login as user-b
  1. Both tokens are stored correctly in the macOS Keychain as separate entries:
(service="gh:github.com", account="user-a") → token-a
(service="gh:github.com", account="user-b") → token-b
  1. Verify with security:
security find-generic-password -s "gh:github.com" -a "user-a" -w  # → token-a ✓
security find-generic-password -s "gh:github.com" -a "user-b" -w  # → token-b ✓
  1. But gh auth token returns the wrong token for one of the configs:
GH_CONFIG_DIR=~/.config/gh-personal gh auth status
# → "Logged in to github.com account user-b (keyring)" ✓

GH_CONFIG_DIR=~/.config/gh-personal gh auth token
# → token-a ✗ (wrong! should be token-b)

GH_CONFIG_DIR=~/.config/gh-personal gh api user --jq '.login'
# → "user-a" ✗

Root cause

The keychain lookup appears to query by service name only (gh:github.com) without passing the account field. macOS Keychain returns an arbitrary entry when multiple entries share the same service name. gh auth status reads the username from hosts.yml (correct), but the actual token retrieval doesn't use it as a filter.

Workaround

Read the keychain entry directly with the correct account and set GH_TOKEN:

_gh_token() {
  local raw
  raw=$(security find-generic-password -s "gh:github.com" -a "$1" -w 2>/dev/null) || return 1
  echo "${raw#go-keyring-base64:}" | base64 -d
}

GH_CONFIG_DIR=~/.config/gh-personal \
  GH_TOKEN=$(_gh_token user-b) \
  gh api user --jq '.login'
# → "user-b" ✓

Expected behavior

gh auth token (and all commands that retrieve the token) should pass the account name from hosts.yml to the keychain lookup, so that multiple accounts for the same host can coexist.

Environment

  • gh version: 2.74.0
  • OS: macOS 15.5 (Darwin 25.3.0)
  • Keychain backend: macOS Keychain (via go-keyring)

Activity

  1. github-actions commented on Mar 9, 2026

    @github-actions
    Contributor

    Thank you for your issue! We have categorized it as an enhancement (feature or improvement) request, and it has been added to our backlog. In doing so, we are not committing to implementing this feature at this time, but, we will consider it for future releases based on community feedback and our own product roadmap.

    Unless you see the help wanted Contributions welcome label, we are not currently looking for external contributions for this feature.

    If you come across this issue and would like to see it implemented, please add a thumbs up! This will help us prioritize the feature. Please only comment if you have additional information or viewpoints to contribute.

  2. added a commit that references this issue on Apr 9, 2026
    cfef0b7
  3. galamdring commented on Apr 9, 2026

    @galamdring

    I've traced this to TokenFromKeyring in internal/keyring/keyring.go — it looks up by service only (gh:github.com), so when multiple accounts share the same host, macOS Keychain returns an arbitrary entry. TokenFromKeyringForUser already does the correct per-user lookup, but ActiveToken only calls it after resolving the globally active user, so the account field is effectively ignored.

    I've implemented a fix in cli/cli#13130 that approaches this from the usage side: a new gh auth set-user --owner <org> <username> command stores an owner→user mapping in hosts.yml, and httpClientFunc in the factory resolves the repo owner from the git remote and selects the correct authenticated user before making any API call. No signature changes to tokenGetter or AddAuthTokenHeader, falls back gracefully to the globally active user when no mapping exists.

    All existing tests pass and new table-driven tests cover the owner mapping behaviour.
    Would the maintainers be open to adding help_wanted to this issue? The bot will auto-close my PR in 7 days without it, and I think this is a real pain point for anyone using gh across multiple accounts on the same machine.

  4. added 5 commits that reference this issue on Apr 19, 2026
    8bf7f5d
    90f4802
    84178a0
    bcf0db7
    2a72777
  5. added a commit that references this issue on May 11, 2026
    0286204
  6. added a commit that references this issue on May 18, 2026
    b7e8f59
  7. added a commit that references this issue on May 25, 2026
    bf26e33
  8. added 3 commits that reference this issue on Aug 13, 2026
    07c1198
    f59f502
    0aa00cc
  9. added a commit that references this issue on Aug 24, 2026
    ebf5054
  10. added a commit that references this issue on Aug 31, 2026
    10e095f
  11. added a commit that references this issue on Sep 19, 2026
    058b8e5
  12. added a commit that references this issue on Sep 28, 2026
    1b5af76
  13. added a commit that references this issue on Oct 5, 2026
    b184ca5
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementa request to improve CLIgh-authrelating to the gh auth commandstale

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions