Collapsing Auth Entropy to Zero: Debugging GitHub Credential Conflicts on Linux
A routine git push failed. What followed was a 20-minute
rabbit hole through five layers of GitHub authentication, a rogue
environment variable injected by an IDE, and the realization that
credential entropy is a silent DevOps killer.
This post documents the entire debugging journey with diagrams, commands, and the exact steps to reach zero auth entropy — one identity, two transports, no conflicts.
🔥 The Symptom
git push origin main
remote: Invalid username or token.
fatal: Authentication failed for 'https://gitlab.com/nurazhar/homepage.git/'
A simple push to a repo. Should take 2 seconds. Instead, it opened a can of worms.
🗺️ The Credential Resolution Hierarchy
Before diving into commands, it helps to understand how
GitHub CLI (gh) and Git resolve credentials. They
don’t just check one place — they walk a priority chain, and the first
match wins:
The critical insight: If GITHUB_TOKEN
is set — even to garbage — gh and Git will use it and
never fall through to the perfectly valid keyring token
below.
🔍 The Audit
Step 1: Check
gh auth status
gh auth status
github.com
✗ Failed to log in to github.com using token (GITHUB_TOKEN)
- Active account: true
- The token in GITHUB_TOKEN is invalid.
✓ Logged in to github.com account nurazhardotcom (keyring)
- Active account: false ← buried under the broken token
- Git operations protocol: https
- Token: [REDACTED]
- Token scopes: 'delete_repo', 'gist', 'read:org', 'repo', 'workflow'
Two accounts. The broken one is active. The valid one is inactive. That’s the bug.
Step 2: Find the rogue token
env | grep GITHUB_TOKEN
GITHUB_TOKEN=[REDACTED]
A dummy placeholder token injected by the IDE
process into every spawned shell. It’s not a real token — it’s a
sentinel value — but gh doesn’t know that. It just sees
GITHUB_TOKEN is set and tries to use it.
Step 3: Trace the source
grep -rl "github_pat_antigravity" ~/.config/ ~/.local/
~/ .local/share/antigravity-ide/resources/app/extensions/.../language_server_linux_x64
~/ .local/bin/agy
It’s baked into the IDE binary. You can’t delete it — you have to override it.
Step 4: Check SSH
ssh -T git@github.com
git@github.com: Permission denied (publickey).
SSH key exists on disk (~/.ssh/id_ed25519) but was
never registered on GitHub. Dead weight.
Step 5: Check Git credential helper
git config --global credential.helper
# (empty — none set)
cat ~/.git-credentials
# No such file
Clean. Nothing stale here.
📊 The Entropy Map
Here’s what the full credential landscape looked like before the fix:
Five credential slots. One broken and blocking. One valid but buried. One half-configured. Two empty. Pure entropy.
🔧 The Fix (4 Commands)
1. Switch active account to the keyring token
unset GITHUB_TOKEN
gh auth switch --user nurazhardotcom
# ✓ Switched active account for github.com to nurazhardotcom
2. Override the dummy token permanently in fish config
echo 'set -gx GITHUB_TOKEN (gh auth token 2>/dev/null)' >> ~/.config/fish/config.fish
Every new shell now reads the real token from
gh auth, overriding whatever the IDE injects.
3. Register the SSH key on GitHub
gh auth refresh -h github.com -s admin:public_key
# (authorize in browser)
gh ssh-key add ~/.ssh/id_ed25519.pub --title "CachyOS laptop"
# ✓ Public key added to your account
4. Verify everything
unset GITHUB_TOKEN && gh auth status
# ✓ Logged in to github.com account nurazhardotcom (keyring)
# - Active account: true
ssh -T git@github.com
# Hi nurazhardotcom! You've successfully authenticated
✅ The Final State — Zero Entropy
| Credential | Status |
|---|---|
| Keyring token (HTTPS) | ✅ Active, valid, primary |
| SSH key | ✅ Registered on GitHub |
config.fish override |
✅ Neutralizes IDE dummy token |
| Classic PAT | 🗑️ Deleted — nothing depends on it |
~/.git-credentials |
✅ Does not exist |
One identity. Two transports. No conflicts. Zero entropy.
🧠 Lessons Learned
Environment variables win. If
GITHUB_TOKENis set,ghand Git will use it — even if it’s garbage. Always checkenv | grep GITHUBbefore debugging auth failures.IDEs inject things. Development environments often set environment variables for their own internal use. These can silently override your carefully configured credentials.
Audit all five credential slots. When auth fails, don’t just re-generate a token. Check the full chain: env vars → keyring → SSH → credential files → credential helper.
SSH keys need two halves. A key on disk without a matching registration on GitHub is dead weight. Always verify with
ssh -T git@github.com.gh auth statusis your friend. It shows you the complete picture — which accounts exist, which is active, and what’s broken.
📋 Quick Reference: Auth Debugging Cheatsheet
| Command | What it checks |
|---|---|
gh auth status |
OAuth/keyring tokens, active account |
env \| grep GITHUB |
Environment variable overrides |
ssh -T git@github.com |
SSH key registration |
cat ~/.git-credentials |
Stored plaintext credentials |
git config credential.helper |
Credential helper configuration |