GitPersonal Access Tokens

Personal Access Tokens (PATs)

A Personal Access Token is a long random string GitHub generates on your behalf that you use instead of your password for anything that goes through HTTPS or the REST API. GitHub removed password auth for Git operations back in August 2021, so if you push over HTTPS you are using a PAT (or an SSH key — see the previous page). They expire, they have explicit scopes, and you can revoke them individually.

Why PATs exist
  • Your account password is too dangerous to type into scripts and CI runners — it unlocks everything.

  • PATs are revocable: leak one, delete it, generate a new one. The password stays safe.

  • PATs have scopes: a token that can only read repos cannot be used to delete them.

  • They have expiry dates: stolen tokens become useless after the deadline.

  • They show up in audit logs — you can see exactly which token did what.

Two flavours: classic vs fine-grained

Classic PAT

Fine-grained PAT

Scope model

Coarse: repo, workflow, packages...

Per-repository, per-permission

Org control

Org owners cannot disallow

Org owners can require approval

Expiration

Optional (you can pick "never")

Required, max 1 year

UI label

Tokens (classic)

Fine-grained tokens

Use when

Older tools, GHE Server compatibility

New work — recommended

Status

Will be deprecated eventually

Preferred going forward

Creating a token, click by click
  • Go to github.com → Settings → Developer settings → Personal access tokens.

  • Pick Fine-grained tokens (recommended) or Tokens (classic).

  • Click Generate new token. Re-authenticate with 2FA if asked.

  • Name it after where it will live: laptop-https-push, ci-deploy-staging, dependabot-bot.

  • Set an expiration date. Pick the shortest you can tolerate. 30 or 90 days is a good default.

  • For fine-grained: pick a Resource owner (you or an org), then choose specific repos.

  • Tick only the permissions you actually need. Least privilege is the rule.

  • Click Generate. Copy the token immediately — once you leave the page it is gone forever.

Picking scopes — the least-privilege checklist

Goal

Classic scope

Fine-grained permission

Clone/pull public repos only

public_repo

Contents: Read (public)

Clone/push private repos

repo

Contents: Read & Write

Use the gh CLI normally

repo, read:org, workflow

Contents R/W, Metadata R, Workflows R/W

Trigger workflows / read CI

workflow

Actions: Read & Write

Publish to GitHub Packages

write:packages

Packages: Read & Write

Manage repo settings

admin:repo_hook, admin:org

Administration: Read & Write

Pause before each checkbox: do I really need write here? Do I really need org admin? Most day-to-day tokens need almost nothing.

Using a PAT to push

The first HTTPS push prompts you

Bash
git push
# Username for 'https://github.com': you
# Password for 'https://you@github.com': <paste the PAT here>
# (your real account password will NOT work)
Storing PATs in a credential helper

Typing a 90-character random string for every push is painful. Git's credential helpers cache the PAT securely in your OS keychain so subsequent pushes are silent.

One-time setup per OS

Bash
# macOS — uses the system keychain
git config --global credential.helper osxkeychain

# Windows — Git for Windows ships Git Credential Manager
git config --global credential.helper manager

# Linux with libsecret (GNOME) — best option
sudo apt install libsecret-1-0 libsecret-1-dev
sudo make --directory=/usr/share/doc/git/contrib/credential/libsecret
git config --global credential.helper /usr/share/doc/git/contrib/credential/libsecret/git-credential-libsecret

# Fallback (plain-text storage — only on trusted machines!)
git config --global credential.helper store

After setup, your first push caches the PAT

Bash
git push
# Username: you
# Password: <paste PAT once>
# Subsequent pushes are silent.
Using gh to handle PATs for you

The easy button

Bash
gh auth login
# ? Where do you use GitHub? -> GitHub.com
# ? Preferred protocol for Git -> HTTPS
# ? Authenticate -> Login with a web browser
# (browser flow generates a PAT and stores it for you)

# After this, both gh and git use the same token transparently.
git push   # silent
Rotating a PAT

A small ritual you should do every quarter

Bash
# 1. Generate a new PAT in Settings -> Developer settings.
# 2. Update credential helper:
git credential-osxkeychain erase <<EOF
host=github.com
protocol=https
EOF

# 3. Next push prompts; paste the new token.
git push

# 4. Delete the old token in Settings (don't just let it expire).
Where PATs go wrong
  • Committed to a repo by accident — anyone who clones can see it. GitHub scans for leaked tokens and revokes them, but assume it leaked the moment you pushed.

  • Sent in a screenshot or chat — same thing. Revoke it now.

  • Stored in CI as a plaintext env var visible in logs — use secrets, never echo it.

  • Used with too many scopes — when stolen, attacker can do more damage. Always least-privilege.

  • No expiration — stays valid until you remember to delete it. Always set an expiry.

Detecting and recovering from a leak

Scan your repo history for accidental tokens

Bash
# Tools like trufflehog, gitleaks, or detect-secrets
brew install trufflehog
trufflehog git file://. --only-verified

# If you find one:
# 1. Go to Settings -> Developer settings -> revoke the token NOW.
# 2. Rotate. Don't rewrite history hoping no one cloned — assume they did.
# 3. Add a pre-commit hook so it can't happen again.
SSH vs PAT — when to use which

Scenario

Recommended

Daily Git pushes from your laptop

SSH key

CI runner that builds and pushes

Fine-grained PAT (least scopes)

Calling the REST API from a script

Fine-grained PAT

Corporate network blocks port 22

PAT over HTTPS

Bot account that opens PRs

Fine-grained PAT or GitHub App

Warning
Treat a PAT exactly like a password — because it is one. Never paste it into chat (including this assistant), never commit it, never log it, never share screenshots that include it. If you suspect it has leaked, revoke it before you finish reading this sentence and rotate everywhere it was used.
Tokens beat passwords on every axis
A PAT is more secure than a password (scoped, expiring, revocable, audit-logged) and less convenient than an SSH key (no agent, must rotate). For laptops, prefer SSH. For machines and scripts, prefer fine-grained PATs with the minimum scopes and a short expiry.
Tip
Name your PATs descriptively (`ci-deploy`, `laptop-https`, `release-bot`) so a year later you can tell which one to rotate or revoke. The Last Used column on the tokens page also helps you spot stale tokens to delete.