Shun's org notes
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:

  1. (Recommended by Forge) Classic tokens are repo-wide at best and account-wide at worst, and a lot of orgs ban them outright.
  2. 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: emacs security
Other posts · Tags