GitHub revoked your personal access token? Why, and how to replace it on Mac

The reasons GitHub gives for revoking a token, how to tell which one hit you, and every place on a Mac the dead token is still saved. The errors and commands below were run on macOS 27 with Apple Git 2.54 and GitHub CLI 2.102.

Pushes that worked yesterday now fail, a script gets 401 Bad credentials, or GitHub sent an email saying a token was revoked. A revoked token cannot be brought back: GitHub's token expiration and revocation page says you have to create a new one. So the work is finding out why it was revoked, which tells you whether you also have a leak to clean up, and then replacing the old value everywhere your Mac has it saved.

What a revoked token looks like

Over HTTPS, git push, git pull on a private repository and git clone of one all fail like this:

remote: Invalid username or token. Password authentication is not supported for Git operations.
fatal: Authentication failed for 'https://github.com/OWNER/REPO/'

The REST API answers with HTTP 401:

{
  "message": "Bad credentials",
  "documentation_url": "https://docs.github.com/rest",
  "status": "401"
}

Two traps. Cloning or fetching a public repository can keep working with a dead token, so a broken token often shows up first on the push. And the same error appears for a token that was never valid, such as a typo or your account password, which GitHub stopped accepting for Git operations.

Why GitHub revoked it

GitHub's revocation page lists these causes for personal access tokens:

To see which happened, open GitHub, click your profile picture, Settings, then Security log under "Archives" (reviewing your security log). The revocation page says an expired or revoked token may show up there as oauth_authorization.destroy. Also check the token list itself: Settings, Developer settings, Personal access tokens, then Fine-grained tokens or Tokens (classic), and look for the token's name and expiration.

If it was pushed or posted publicly

The revocation already killed the token, which is the urgent step done for you. Three things are still yours:

Make the replacement

In Settings, Developer settings, Personal access tokens, create a fine-grained or classic token with only the repositories and permissions the job needs, and an expiration date. Copy the value from the page GitHub shows after you generate it, straight to where it is going. The prefix tells you what you have: ghp_ is a classic token and github_pat_ a fine-grained one (GitHub's token formats).

Replace it in the Keychain, for git over HTTPS

First find out where git keeps the token. On a Mac using Apple's git, this usually prints osxkeychain, set in the system gitconfig that ships with Apple's developer tools:

git config --show-origin --get-all credential.helper

osxkeychain keeps the token as an "Internet password" item for github.com in your login keychain. When the server rejects a saved credential, git asks the helper to erase it (the reject step described in git credential), so the next push often prompts on its own. If it keeps failing without asking, erase the item yourself, as in GitHub's updating credentials from the macOS Keychain:

git credential-osxkeychain erase
host=github.com
protocol=https

Type the two lines, then press Return on an empty line. Or open Keychain Access, search for github.com and delete or edit the "Internet password" item. To check whether an item exists without showing the password (that needs -g or -w):

security find-internet-password -s github.com

On the next push, enter your GitHub username, and paste the new token when git asks for a password.

store means the token sits unencrypted in ~/.git-credentials (git-credential-store). Edit the github.com line, or delete the line and push again. A token inside the remote URL, such as https://ghp_…@github.com/OWNER/REPO, is sent on every push whatever the helper holds. Check with git remote -v and fix it with git remote set-url origin https://github.com/OWNER/REPO.git.

Replace it for the GitHub CLI

gh auth status tests each saved account and exits with 1 when one has a problem. Run gh auth login to sign in again. Then gh auth setup-git makes git use gh as its credential helper, so git and gh share one login.

If gh keeps failing after a fresh login, look for an old token in your environment. GH_TOKEN and GITHUB_TOKEN take precedence over stored credentials (gh help environment). This shows which are set, without printing the values:

env | grep -E '^(GH|GITHUB)_TOKEN=' | cut -d= -f1

Find the other copies of the old token

A personal access token tends to get pasted into more places than anyone remembers: a shell profile, a project .env file, ~/.netrc, an .npmrc for GitHub Packages, a CI secret. Each one fails separately until you replace it. To list files that contain anything shaped like a GitHub token, with names only and no values printed:

grep -IlE 'gh[pousr]_[A-Za-z0-9]{36}|github_pat_[A-Za-z0-9_]{82}' \
  ~/.zshrc ~/.zprofile ~/.bashrc ~/.bash_profile ~/.netrc ~/.git-credentials ~/.npmrc 2>/dev/null

grep -rIlE --exclude-dir=node_modules --exclude-dir=.git \
  'gh[pousr]_[A-Za-z0-9]{36}|github_pat_[A-Za-z0-9_]{82}' ~/Projects

Change ~/Projects to wherever your code lives. Remove each match, or put the new token in it, and open a new terminal so the shell reloads the profile. If you ever typed export GITHUB_TOKEN=…, it is also in your shell history: see the guides for .zsh_history, .bash_history and fish history, and how to keep secrets out of shell history for next time. CI systems and other machines need the new value too; nothing on your Mac can update those.