Skip to content

secure keyring storage doesn't work with KeepassXC #8691

Description

@m00nwtchr

Describe the bug

Logging in with gh auth login seems successful, but it appears that the cli cannot retrieve the token from KeepassXC.
It does seem to be saved correctly in KeepassXC.

gh version 2.43.1 (2024-01-31)

Steps to reproduce the behavior

  1. Setup the KeepassXC Secret Service feature. (e.g. https://avaldes.co/2020/01/28/secret-service-keepassxc.html)
  2. Ensure that no other secret service is running
  3. Log in with gh auth login
  4. Use any command which requires authentication.
  5. See auth error.

Logs

❯ gh auth login
? What account do you want to log into? GitHub.com
? What is your preferred protocol for Git operations on this host? SSH
? Generate a new SSH key to add to your GitHub account? No
? How would you like to authenticate GitHub CLI? Login with a web browser

! First copy your one-time code: F8A4-A179
Press Enter to open github.com in your browser...
✓ Authentication complete.
- gh config set -h github.com git_protocol ssh
✓ Configured git protocol
✓ Logged in as m00nwtchr
! You were already logged in to this account
❯ gh repo list
HTTP 401: This endpoint requires you to be authenticated. (https://api.github.com/graphql)
Try authenticating with:  gh auth login
❯ keyring get gh:github.com m00nwtchr
<oauth token>

Activity

  1. williammartin commented on Feb 13, 2024

    @williammartin
    Member

    What's the output of gh auth status?

  2. added
    more-info-neededMore info needed from user/contributor
    and removed on Feb 13, 2024
  3. m00nwtchr commented on Feb 21, 2024

    @m00nwtchr
    Author
    ❯ gh auth status
    github.com
      X Failed to log in to github.com account m00nwtchr (/home/m00n/.config/gh/hosts.yml)
      - Active account: true
      - The token in /home/m00n/.config/gh/hosts.yml is invalid.
      - To re-authenticate, run: gh auth login -h github.com
      - To forget about this account, run: gh auth logout -h github.com -u m00nwtchr
    

    /home/m00n/.config/gh/hosts.yml:

    github.com:
        git_protocol: ssh
        users:
            m00nwtchr:
        user: m00nwtchr
    
  4. williammartin commented on Feb 21, 2024

    @williammartin
    Member

    Thanks. So most likely what is happening is that the keyring is returning an error here but it is being swallowed:

    token, err = c.TokenFromKeyring(hostname)
    if err == nil {
    source = "keyring"
    }

    There's some legacy reasons for this fallback that relate to the previous default of --insecure-storage but it's all round pretty annoying because it hides what's going on 🙄 . It's also deeply misleading because your token isn't really in hosts.yml, it just doesn't exist at all. We can probably fix the latter error message.

    If I created a branch with some additional debug information, would you be willing to build it locally and try it out?

  5. m00nwtchr commented on Feb 21, 2024

    @m00nwtchr
    Author

    Sure

  6. williammartin commented on Apr 4, 2024

    @williammartin
    Member

    @Kobaxidze256 since you're using KeePassXC I suspect that this is probably the right place to track your issue. Looks like I let it go stale though during a busy time, sorry for that @m00nwtchr !

  7. added and removed
    more-info-neededMore info needed from user/contributor
    on Apr 4, 2024
  8. Kobaxidze256 commented on Apr 19, 2024

    @Kobaxidze256

    Thanks. So most likely what is happening is that the keyring is returning an error here but it is being swallowed:

    token, err = c.TokenFromKeyring(hostname)
    if err == nil {
    source = "keyring"
    }

    There's some legacy reasons for this fallback that relate to the previous default of --insecure-storage but it's all round pretty annoying because it hides what's going on 🙄 . It's also deeply misleading because your token isn't really in hosts.yml, it just doesn't exist at all. We can probably fix the latter error message.

    If I created a branch with some additional debug information, would you be willing to build it locally and try it out?

    @williammartin yes

  9. Kobaxidze256 commented on Apr 19, 2024

    @Kobaxidze256

    Also, hello from April (I wasn't busy)

  10. j-asn commented on May 1, 2024

    @j-asn

    I have the same issue with KeePassXC. I looked at the output from dbus-monitor when running gh auth status (before this I have already authenticated and the token is stored in KeePassXC):

    Details
    method call time=1714569192.305506 sender=:1.99 -> destination=org.freedesktop.secrets serial=2 path=/org/freedesktop/secrets; interface=org.freedesktop.DBus.Properties; member=Get
       string "org.freedesktop.Secret.Service"
       string "Collections"
    method call time=1714569192.305631 sender=:1.87 -> destination=org.freedesktop.DBus serial=216 path=/org/freedesktop/DBus; interface=org.freedesktop.DBus; member=GetConnectionUnixProcessID
       string ":1.99"
    method return time=1714569192.305636 sender=org.freedesktop.DBus -> destination=:1.87 serial=4294967295 reply_serial=216
       uint32 78309
    method call time=1714569192.305925 sender=:1.87 -> destination=org.freedesktop.DBus serial=217 path=/org/freedesktop/DBus; interface=org.freedesktop.DBus; member=GetConnectionUnixProcessID
       string ":1.99"
    method return time=1714569192.305931 sender=org.freedesktop.DBus -> destination=:1.87 serial=4294967295 reply_serial=217
       uint32 78309
    method call time=1714569192.306290 sender=:1.87 -> destination=org.freedesktop.DBus serial=218 path=/org/freedesktop/DBus; interface=org.freedesktop.DBus; member=AddMatch
       string "type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='NameOwnerChanged',arg0=':1.99',arg2=''"
    method return time=1714569192.306303 sender=:1.87 -> destination=:1.99 serial=219 reply_serial=2
       variant       array [
             object path "/org/freedesktop/secrets/collection/keys"
          ]
    method call time=1714569192.306411 sender=:1.99 -> destination=org.freedesktop.secrets serial=3 path=/org/freedesktop/secrets; interface=org.freedesktop.Secret.Service; member=Unlock
       array [
          object path "/org/freedesktop/secrets/aliases/default"
       ]
    method return time=1714569192.306488 sender=:1.87 -> destination=:1.99 serial=220 reply_serial=3
       array [
          object path "/org/freedesktop/secrets/collection/keys"
       ]
       object path "/"
    method call time=1714569192.306586 sender=:1.99 -> destination=org.freedesktop.secrets serial=4 path=/org/freedesktop/secrets/aliases/default; interface=org.freedesktop.Secret.Collection; member=SearchItems
       array [
          dict entry(
             string "username"
             string ""
          )
          dict entry(
             string "service"
             string "gh:github.com"
          )
       ]
    method return time=1714569192.306722 sender=:1.87 -> destination=:1.99 serial=221 reply_serial=4
       array [
          object path "/org/freedesktop/secrets/collection/keys/c1379413632447999548e698e9e95c3b"
       ]
    method call time=1714569192.306795 sender=:1.99 -> destination=org.freedesktop.secrets serial=5 path=/org/freedesktop/secrets; interface=org.freedesktop.Secret.Service; member=OpenSession
       string "plain"
       variant       string ""
    method return time=1714569192.306864 sender=:1.87 -> destination=:1.99 serial=222 reply_serial=5
       variant       string ""
       object path "/org/freedesktop/secrets/session/eebc9f5c16d441caa38d6804bce7ebbe"
    method call time=1714569192.306936 sender=:1.99 -> destination=org.freedesktop.secrets serial=6 path=/org/freedesktop/secrets/collection/keys/c1379413632447999548e698e9e95c3b; interface=org.freedesktop.Secret.Item; member=GetSecret
       object path "/org/freedesktop/secrets/session/eebc9f5c16d441caa38d6804bce7ebbe"
    error time=1714569192.306988 sender=:1.87 -> destination=:1.99 error_name=org.freedesktop.Secret.Error.IsLocked reply_serial=6
    method call time=1714569192.307057 sender=:1.99 -> destination=org.freedesktop.secrets serial=7 path=/org/freedesktop/secrets/session/eebc9f5c16d441caa38d6804bce7ebbe; interface=org.freedesktop.Secret.Session; member=Close
    method return time=1714569192.307101 sender=:1.87 -> destination=:1.99 serial=224 reply_serial=7
    

    I'm no expert on the details here but it looks to me like it might be failing because of the confirmation prompt that KeePassXC throws up when secrets are accessed. If I disable that confirmation prompt (uncheck Settings > Secret Service Integration > Confirm when passwords are retrieved by clients) then it works fine. Here's the dbus-monitor output from that case:

    Details
    method call time=1714570624.583322 sender=:1.103 -> destination=org.freedesktop.secrets serial=2 path=/org/freedesktop/secrets; interface=org.freedesktop.DBus.Properties; member=Get
       string "org.freedesktop.Secret.Service"
       string "Collections"
    method call time=1714570624.583476 sender=:1.87 -> destination=org.freedesktop.DBus serial=236 path=/org/freedesktop/DBus; interface=org.freedesktop.DBus; member=GetConnectionUnixProcessID
       string ":1.103"
    method return time=1714570624.583481 sender=org.freedesktop.DBus -> destination=:1.87 serial=4294967295 reply_serial=236
       uint32 79763
    method call time=1714570624.583945 sender=:1.87 -> destination=org.freedesktop.DBus serial=237 path=/org/freedesktop/DBus; interface=org.freedesktop.DBus; member=GetConnectionUnixProcessID
       string ":1.103"
    method return time=1714570624.583948 sender=org.freedesktop.DBus -> destination=:1.87 serial=4294967295 reply_serial=237
       uint32 79763
    method call time=1714570624.584319 sender=:1.87 -> destination=org.freedesktop.DBus serial=238 path=/org/freedesktop/DBus; interface=org.freedesktop.DBus; member=AddMatch
       string "type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='NameOwnerChanged',arg0=':1.103',arg2=''"
    method return time=1714570624.584354 sender=:1.87 -> destination=:1.103 serial=239 reply_serial=2
       variant       array [
             object path "/org/freedesktop/secrets/collection/keys"
          ]
    method call time=1714570624.584435 sender=:1.103 -> destination=org.freedesktop.secrets serial=3 path=/org/freedesktop/secrets; interface=org.freedesktop.Secret.Service; member=Unlock
       array [
          object path "/org/freedesktop/secrets/aliases/default"
       ]
    method return time=1714570624.584522 sender=:1.87 -> destination=:1.103 serial=240 reply_serial=3
       array [
          object path "/org/freedesktop/secrets/collection/keys"
       ]
       object path "/"
    method call time=1714570624.584619 sender=:1.103 -> destination=org.freedesktop.secrets serial=4 path=/org/freedesktop/secrets/aliases/default; interface=org.freedesktop.Secret.Collection; member=SearchItems
       array [
          dict entry(
             string "username"
             string ""
          )
          dict entry(
             string "service"
             string "gh:github.com"
          )
       ]
    method return time=1714570624.584751 sender=:1.87 -> destination=:1.103 serial=241 reply_serial=4
       array [
          object path "/org/freedesktop/secrets/collection/keys/c1379413632447999548e698e9e95c3b"
       ]
    method call time=1714570624.584845 sender=:1.103 -> destination=org.freedesktop.secrets serial=5 path=/org/freedesktop/secrets; interface=org.freedesktop.Secret.Service; member=OpenSession
       string "plain"
       variant       string ""
    method return time=1714570624.584915 sender=:1.87 -> destination=:1.103 serial=242 reply_serial=5
       variant       string ""
       object path "/org/freedesktop/secrets/session/4236faae09bd442b9b7954e57d994c03"
    method call time=1714570624.584985 sender=:1.103 -> destination=org.freedesktop.secrets serial=6 path=/org/freedesktop/secrets/collection/keys/c1379413632447999548e698e9e95c3b; interface=org.freedesktop.Secret.Item; member=GetSecret
       object path "/org/freedesktop/secrets/session/4236faae09bd442b9b7954e57d994c03"
    method return time=1714570624.585057 sender=:1.87 -> destination=:1.103 serial=243 reply_serial=6
       struct {
          object path "/org/freedesktop/secrets/session/4236faae09bd442b9b7954e57d994c03"
          array [
          ]
          array of bytes "<the token value>"
          string "text/plain"
       }
    method call time=1714570624.585139 sender=:1.103 -> destination=org.freedesktop.secrets serial=7 path=/org/freedesktop/secrets/session/4236faae09bd442b9b7954e57d994c03; interface=org.freedesktop.Secret.Session; member=Close
    
    
  11. williammartin commented on May 1, 2024

    @williammartin
    Member

    Thanks for the logs @j-asn, taking a snippet from your first log:

    method call time=1714569192.306795 sender=:1.99 -> destination=org.freedesktop.secrets serial=5 path=/org/freedesktop/secrets; interface=org.freedesktop.Secret.Service; member=OpenSession
       string "plain"
       variant       string ""
    method return time=1714569192.306864 sender=:1.87 -> destination=:1.99 serial=222 reply_serial=5
       variant       string ""
       object path "/org/freedesktop/secrets/session/eebc9f5c16d441caa38d6804bce7ebbe"
    method call time=1714569192.306936 sender=:1.99 -> destination=org.freedesktop.secrets serial=6 path=/org/freedesktop/secrets/collection/keys/c1379413632447999548e698e9e95c3b; interface=org.freedesktop.Secret.Item; member=GetSecret
       object path "/org/freedesktop/secrets/session/eebc9f5c16d441caa38d6804bce7ebbe"
    error time=1714569192.306988 sender=:1.87 -> destination=:1.99 error_name=org.freedesktop.Secret.Error.IsLocked reply_serial=6
    

    When gh uses the zalando-gokeyring library to get a secret, we end up sending a dbus OpenSession message followed by a GetSecret message, which we see reflected in the logs.

    Instead of returning the secret (as in your second log), we see:

    error time=1714569192.306988 sender=:1.87 -> destination=:1.99 error_name=org.freedesktop.Secret.Error.IsLocked reply_serial=6
    

    I don't know much about keepass though keepassxreboot/keepassxc#4004 looks kind of interesting.

  12. m00nwtchr commented on May 1, 2024

    @m00nwtchr
    Author

    Looks like this is a known issue in that lib: zalando/go-keyring#88

  13. williammartin commented on Jun 7, 2024

    @williammartin
    Member

    @m00nwtchr, @Kobaxidze256, @j-asn, would you be up for building from trunk and checking if the #9179 has resolved this issue?

  14. m00nwtchr commented on Jun 7, 2024

    @m00nwtchr
    Author

    Should be able to in a few hours.

  15. m00nwtchr commented on Jun 7, 2024

    @m00nwtchr
    Author

    @williammartin Can confirm that the issue has been resolved.

  16. williammartin commented on Jun 7, 2024

    @williammartin
    Member

    Woohoo, great work @AlanD20 !

  17. AlanD20 commented on Jun 7, 2024

    @AlanD20
    Contributor

    That's awesome!!

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

    bugSomething isn't workinggh-authrelating to the gh auth commandneeds-triageneeds to be reviewed

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions