28 Aug 2026
magit forge auth: gh token in pass
Forge gives you PRs, issues, and code reviews inside Magit, but it needs a GitHub token to hit the API. I don't like either of the stock options:
- (Recommended by Forge) Classic tokens are repo-wide at best and account-wide at worst, and a lot of orgs ban them outright.
- Fine-grained tokens are scoped per-owner, so I'd need separate tokens for each org, plus a way to switch between them in Forge.
The gh CLI already solved the hard part of auth: browser-based OAuth with device flow, SSO included. I don't want to reinvent that, so my (slightly cursed) approach is: let gh do the heavy-lifting, then capture the token, and stash it in password-store (pass):
#!/usr/bin/env bash
tmp=$(mktemp -d)
trap 'rm -rf $tmp' EXIT
export GH_CONFIG_DIR=$tmp
# --insecure-storage stores the token as plaintext in GH_CONFIG_DIR instead
# of the native keychain. I don't want to pollute the global state, and the
# token is persisted in pass.
gh auth login --web --insecure-storage --git-protocol ssh --skip-ssh-key --clipboard
token=$(gh auth token)
<<<"$token" pass insert -mf "ApiKeys/GH_TOKEN"
Now Emacs reads it back out, using auth-source's native pass support. Forge's API client, ghub, asks for a token, and I override ghub--token to pull it from pass:
;; Enable pass for auth-source
(auth-source-pass-enable)
(use-package forge
:after magit
:config
(advice-add 'ghub--token :override
(lambda (&rest _)
(string-trim (auth-source-pass-get 'secret "ApiKeys/GH_TOKEN")))))
Tags: