Skip to main content

GitHub Token Access Verification

Verify a GitHub token's access to a repo before clone/push. Partners with github-auth (which covers creating credentials). This skill covers the other half: confirming a token actually reaches a specific repo before you trust it with a clone/push, and managing multiple tokens when each is a fine-grained PAT scoped to a different org or repo allowlist.

When to use​

  • A clone/push refused with 403 "Write access to repository not granted" or an API call returned 404.
  • User says "can you check out this repo now?" with a newly-added token — verify first, don't assume.
  • Environment holds more than one GitHub token and you need to know which one owns which repo.

The fast access check (do this FIRST, before any clone/push)​

A repository GET returning HTTP 200 proves visibility for that credential. A 404 is ambiguous: the repository may be absent or hidden by permissions. When creation is already evidenced, check the credential's repository allowlist rather than recreating the repository. API visibility, Git transport access, and successful push are separate checks.

# Read the token from the env file without printing it
T=$(grep '^GITHUB_PERSONAL_ACCESS_TOKEN_2=' ~/.hermes/.env | cut -d= -f2-)

# API: 200 = access, 404 = not granted
curl -s -o /dev/null -w "%{http_code}\n" \
-H "Authorization: Bearer $T" \
https://api.github.com/repos/OWNER/REPO

# Probe Git with the SAME credential via a process-local credential helper
# or scoped http.extraheader; use a credential-free URL.
# See references/credential-consistent-publication.md for the Python pattern.

Require a successful API GET and successful Git transport exit status. An empty ls-remote with exit 0 is normal for a newly created empty repository; it is not an authentication failure. Neither a populated ref list nor API visibility alone proves write access. Verify the actual authorized push and then read its ref back. Never embed tokens in remote URLs, command arguments, receipts, or output.

When comparing several tokens, loop them and print the HTTP code per token — it makes the "which token owns which repo" question answerable at a glance.

Managing multiple tokens in Hermes​

  • Each token gets its own distinct env var in the Hermes secrets file, e.g. GITHUB_PERSONAL_ACCESS_TOKEN, GITHUB_PERSONAL_ACCESS_TOKEN_2, … There is no collision because each tool/skill reads the specific variable it's wired to.
  • Existing processes may retain earlier environment values. After the user changes access or credentials, securely load the intended credential afresh and test it explicitly before requesting another permission change or a session restart. Default gh, Git helpers and MCP may use different credentials; align the repository probe and push to the credential that actually succeeded.
  • The GitHub MCP server is a separate wiring point: it maps a specific env var in config.yaml (github.env). Pointing a different token at the MCP server means editing that mapping, not just adding an env var.
  • Remember the allowlist rule: even with a correct token, a repo still isn't reachable until the user adds it to that PAT's Repository access in GitHub Settings.

Pitfalls​

  • 404 does not distinguish absent from permission-hidden. Do not repeatedly create a repository after a confirmed creation response. Check the intended credential afresh, and ask for allowlist access only if that credential still fails.
  • Publish an approved candidate without rewriting its identity. Confirm the clean exact SHA, scan the history being published for secrets, verify the remote is empty (or reconcile existing refs), push only the intended SHA/ref, and read back both the Git ref and GitHub commit API SHA. Verify private visibility/default branch. Do not fast-forward or clean a dirty older main checkout merely to publish a newer accepted worktree. See references/credential-consistent-publication.md.
  • Don't echo token values into logs. Read them with grep ... | cut -d= and print only lengths (${#T}) or HTTP codes, never the secret itself.
  • Memory guard quirk: when saving a fact about these tokens to Hermes memory, a write that contains the literal secrets-file path (e.g. under the Hermes home) can be rejected by a threat filter. Rephrase to name the variable without the path (e.g. "env var GITHUB_PERSONAL_ACCESS_TOKEN_2").

Supporting files: this skill's supporting files are held in the docsite at docs/15-skills/_support/github/github-token-access-verification/ — fetch them fresh from jknash/docsite main alongside this page. Source: jknash/hermes-shared-skills · branch hermes-jkdev001 @ 1d0d545c3970 · skills/github/github-token-access-verification/ · view source · Imported 2026-10-04. Supporting files (references, scripts) remain in the source repository.

version 1.0.0 · author Hermes Agent · license MIT.

Published by Muse · 2026-10-04.