To get a GitHub personal access token, sign in to GitHub, go to Settings → Developer settings → Personal access tokens, choose Fine-grained tokens (or Tokens (classic)), click Generate new token, set an expiration and the permissions or scopes you need, then click Generate token. Copy the token immediately — GitHub shows it only once — and use it in the Authorization: Bearer header of your API requests.
That's the short version. The rest of this page covers which token type to pick, exactly which scopes to grant, a working code sample, and the errors you'll hit if a permission is missing.
Prerequisites
- A GitHub account with a verified email address (GitHub blocks token creation until your email is verified).
- Decide your resource owner up front: a fine-grained token is scoped to either your personal account or a single organization you belong to, not both.
- If the token needs to touch an organization's private repos, check whether that org restricts personal access tokens — an org admin may need to approve fine-grained tokens or allow classic PAT access before your token works.
Step-by-step: creating a fine-grained personal access token
GitHub recommends fine-grained tokens over classic tokens for new integrations, because you can scope them to specific repos and specific permissions instead of broad account-wide scopes (GitHub Docs, Managing your personal access tokens).
- In the top-right corner of any GitHub page, click your profile photo, then Settings.
- In the left sidebar, click Developer settings.
- Under Personal access tokens, click Fine-grained tokens, then Generate new token.
- Give it a Token name, and set an Expiration — up to 366 days, or no expiration if your org permits it. For anything long-running, pick the longest allowed expiration and put a renewal reminder on your calendar.
- Under Resource owner, pick your account or the organization whose data you need.
- Under Repository access, choose Only select repositories and pick the repos this token actually needs. "All repositories" works, but it defeats the point of a fine-grained token.
- Under Permissions, grant only what the endpoints you're calling require — for example, Contents: Read-only to read files, or Issues: Read and write to create and comment on issues. Each REST endpoint's doc page lists the exact permission it needs.
- Click Generate token and copy it somewhere safe. If your org requires approval for fine-grained tokens, the token stays in
pendingstate — and read-only on public data — until an admin approves it.
Some endpoints (Packages, the Checks API, public repos you don't own) still don't support fine-grained tokens (limitations). For those, use Tokens (classic) instead: Developer settings → Personal access tokens → Tokens (classic) → Generate new token (classic), name it, set an expiration, check the scopes you need (repo covers most repository read/write cases), and generate. Knit's own GitHub setup guide uses this classic flow with repo, read:org, read:user, and user:email (Knit Docs — GitHub).
Where the credential goes
GitHub's REST API expects the token in a standard bearer header:
Authorization: Bearer YOUR-TOKENGitHub also still accepts the older Authorization: token YOUR-TOKEN form, but Bearer is what current docs and examples use (GitHub Docs, Authenticating to the REST API).
A few things to keep in mind:
- Lifetime: fine-grained tokens expire on the date you set (max 366 days, or no expiration if your org allows it). Classic tokens can be set to never expire, but GitHub auto-revokes any token — classic or fine-grained — that goes unused for a year.
- Refresh: personal access tokens don't refresh themselves. When one expires, you generate a new one and update wherever it's stored — there's no refresh-token flow like OAuth.
- Scopes/permissions: grant the minimum. A fine-grained token with
contents: readcan't accidentally delete a repo; a classic token withrepocan do almost anything to every repo you can access. Store the token in an environment variable or secrets manager — never commit it.
Minimal working example
This calls GET /user, which returns the profile of the token's owner — a good smoke test for any new token.
curl:
curl -H "Authorization: Bearer $GITHUB_TOKEN" \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2026-03-10" \
https://api.github.com/userNode.js:
const res = await fetch("https://api.github.com/user", {
headers: {
Authorization: `Bearer ${process.env.GITHUB_TOKEN}`,
Accept: "application/vnd.github+json",
"X-GitHub-Api-Version": "2026-03-10",
},
});
const data = await res.json();
console.log(data.login);Both send the X-GitHub-Api-Version header, which GitHub recommends pinning so a future API version change doesn't silently alter your response shape (GitHub Docs, Authenticating to the REST API).
Common errors and fixes
Why am I getting "Bad credentials" with a 401?
The token is missing, malformed, expired, or was revoked. Double-check the header reads Authorization: Bearer <token> with no extra quotes or whitespace, and confirm the token still exists under Settings → Developer settings — GitHub auto-deletes personal access tokens that sit unused for a year (GitHub Docs, Managing your personal access tokens).
Why do I get "Resource not accessible by personal access token"?
Your token doesn't have the scope or permission that endpoint needs. For fine-grained tokens, check the response's X-Accepted-GitHub-Permissions header — it lists exactly what's required — then add that permission to the token. For classic tokens, you likely need a broader scope like repo instead of public_repo (GitHub Docs, Troubleshooting the REST API).
Why am I hitting a 403/429 rate limit so quickly?
Unauthenticated requests are capped at 60/hour; authenticated requests get 5,000/hour. If x-ratelimit-remaining is 0, wait until the time in x-ratelimit-reset (UTC epoch seconds) before retrying — retrying immediately just burns more of your secondary rate limit (GitHub Docs, Rate limits for the REST API).
The faster way
Generating and rotating PATs is fine for a single script. It gets messier once you're supporting GitHub alongside Jira, Zendesk, or a dozen other ticketing tools — each with its own auth quirks, scopes, and expiry rules. Knit's unified ticketing API handles GitHub's OAuth and PAT flows, normalizes the endpoints across connectors, and refreshes credentials so you don't have to build that machinery yourself. See the GitHub API overview for what's available, or book a demo to see it against your own GitHub org. You can also sign up free and connect a sandbox GitHub account in a few minutes.
FAQ
Where do I find my GitHub personal access token after creating it?
GitHub shows the token value exactly once, right after you click "Generate token" — copy it then, because it's never displayed again. Lost it? Generate a new one. Existing tokens (without values) live under Settings → Developer settings → Personal access tokens, where you can check scopes, expiration, and delete unused ones.
What's the difference between a fine-grained and a classic personal access token?
Fine-grained tokens scope to specific repos and specific permissions; classic tokens use broad scopes like repo that apply everywhere you have access. Knit's GitHub setup currently uses classic scopes (repo, read:org, read:user, user:email) because a few endpoints — Packages, the Checks API, public repos you don't own — still aren't supported by fine-grained tokens.
Can I use a personal access token to access an organization's repositories?
Yes, if the org allows it and you already have access to those repos — a token can't grant access you don't have. Org admins can restrict or require approval for both token types, so a 403 against org repos usually means a policy setting, not a bad token.
How long does a GitHub personal access token last before I need a new one?
Fine-grained tokens expire on whatever date you set, up to 366 days out, or never if your org's policy allows it. Classic tokens can be set to never expire, but GitHub auto-deletes any token — classic or fine-grained — that sits unused for a year.
Is the GitHub API free to use with a personal access token?
Yes — token creation and REST API calls are free, subject to GitHub's rate limits (5,000 authenticated requests/hour for most accounts). If you're hitting that limit across multiple orgs, a GitHub App is worth a look — installation tokens get up to 15,000/hour on Enterprise Cloud.
Last verified and updated: 2026-06-13
Sources:
- Managing your personal access tokens — GitHub Docs
- Authenticating to the REST API — GitHub Docs
- Rate limits for the REST API — GitHub Docs
- Troubleshooting the REST API — GitHub Docs
- GitHub setup — Knit Docs



