Providers / GitHub
Code hosting
GitHub API keys and credentials
What every GitHub credential a founder holds does, whether it expires, and what tends to break. Each fact links to GitHub's own docs.
At a glance
| Credential | Expiry | Permissions |
|---|---|---|
| GitHub account login | Not documented | – |
| Fine-grained personal access token | You choose | Can be scoped |
| Classic personal access token | You choose | Can be scoped |
| GitHub App private key (PEM) | Doesn't expire | Full access only |
| Deploy key (SSH) | Doesn't expire | Can be scoped |
How to rotate the GitHub fine-grained token
- Create a replacement: Settings > Developer settings > Personal access tokens > Fine-grained tokens, click Generate new token, enter a token name, select an Expiration, choose Repository access, choose Permissions, and click Generate token GitHub docs
- Update wherever the old token was copied. For an Actions secret, the docs describe adding a repository secret (repository Settings, then New repository secret), an environment secret (Environments, pick the environment, then Add secret under Environment secrets) or an organization secret (New organization secret). The page read does not describe editing an existing secret's value in the web UI GitHub docs
- To change an Actions secret through the API, PUT /repos/{owner}/{repo}/actions/secrets/{secret_name} creates or updates it: the body is the value encrypted with LibSodium plus the key_id of the public key used, and the response is 201 on create or 204 on update. The page says classic tokens need the repo scope for this endpoint GitHub docs
- GitHub says organization and repository secrets are read when a workflow run is queued, and environment secrets when a job referencing the environment starts. Run or re-run a workflow after changing the secret GitHub docs
- Delete the old token: on the same Personal access tokens page, click Delete to the right of the token you want to remove GitHub docs
Can the old and new key work at the same time? Yes. Yes, by creating a new token rather than regenerating. A new token is a separate credential, so the old one keeps working until it expires or you delete it. The docs pages read do not describe a Regenerate button or what it keeps (scopes, expiry), so this entry does not use it.
Revoking the old one: Delete the old token from Settings > Developer settings > Personal access tokens. GitHub notes that deleting a token that was used to create a deploy key also deletes that deploy key. A leaked token belonging to someone else can be reported through the REST API revocation route.
Source: docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens, checked
Does the GitHub fine-grained token expire?
It's up to you: you can set an expiry for the GitHub fine-grained token.
What breaks when the GitHub fine-grained token expires
GitHub's token expiration page (https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/token-expiration-and-revocation) says that on reaching its expiration date the token is automatically revoked, and an expired or revoked token cannot be restored; you create a new one. The pages read do not give the exact error that git, the API or Actions returns for an expired token. An organization or enterprise owner can set a maximum lifetime policy that blocks tokens with infinite lifetimes; the pages read do not describe the error returned for a blocked token. The docs do not describe any email sent when a token expires or is about to, and do not say how organization owners are notified.
Other things that often go wrong with GitHub:
- Fine-grained token reaches its chosen expiry and CI pushes or deployments start failing silently
- Organization maximum-lifetime policy blocks a token the team expected to be non-expiring
- Classic token with no expiration is leaked and stays valid indefinitely
- Token removed after a year of inactivity breaks a dormant automation when it is finally used
How to rotate the GitHub classic token
- Create a replacement: Settings > Developer settings > Personal access tokens > Tokens (classic), then Generate new token (classic). Add a note, select an Expiration (a default option or Custom date), select the scopes, and click Generate token GitHub docs
- Update wherever the old token was copied. For an Actions secret, the docs describe adding a repository secret (repository Settings, then New repository secret), an environment secret (Environments, pick the environment, then Add secret under Environment secrets) or an organization secret (New organization secret). The page read does not describe editing an existing secret's value in the web UI GitHub docs
- To change an Actions secret through the API, PUT /repos/{owner}/{repo}/actions/secrets/{secret_name} creates or updates it: the body is the value encrypted with LibSodium plus the key_id of the public key used, and the response is 201 on create or 204 on update. The page says classic tokens need the repo scope for this endpoint GitHub docs
- GitHub says organization and repository secrets are read when a workflow run is queued, and environment secrets when a job referencing the environment starts. Run or re-run a workflow after changing the secret GitHub docs
- Delete the old token: on the same page, click Delete to the right of the token you want to remove GitHub docs
Can the old and new key work at the same time? Yes. Yes, by creating a new token rather than regenerating. A new token is a separate credential, so the old one keeps working until it expires or you delete it. The docs pages read do not describe a Regenerate button or what it keeps (scopes, expiry), so this entry does not use it. The docs read describe the organization lifetime policy only for fine-grained tokens.
Revoking the old one: Delete the old token from Settings > Developer settings > Personal access tokens. GitHub notes that deleting a token that was used to create a deploy key also deletes that deploy key. A leaked token belonging to someone else can be reported through the REST API revocation route.
Source: docs.github.com/en/authentication/keeping-your-account-and-data-secure/token-expiration-and-revocation, checked
Does the GitHub classic token expire?
It's up to you: you can set an expiry for the GitHub classic token.
What breaks when the GitHub classic token expires
GitHub says that on reaching its expiration date the token is automatically revoked, and an expired or revoked token cannot be restored; you create a new one. GitHub also revokes a personal access token that has not been used in one year. The pages read do not give the error returned to git, the API or Actions, and do not describe expiry emails.
How to rotate the GitHub App private key
- Open your account settings from your profile picture (for an organization-owned app, go to Your organizations and click Settings beside the organization), then Developer settings > GitHub Apps GitHub docs
- Click Edit next to the app, go to Credentials, and under Key pairs click New key. Store the downloaded file: GitHub keeps only the public part. The PEM is in PKCS#1 RSAPrivateKey format GitHub docs
- Deploy the new private key to wherever your app signs its JWTs and confirm it works. The docs say to use multiple keys to rotate without downtime GitHub docs
- Under Key pairs, click Delete next to the old key and confirm by clicking Delete again GitHub docs
Can the old and new key work at the same time? Yes. An app can have up to 25 private keys, and GitHub recommends multiple keys so you can rotate without downtime. If the app has only one key you must generate a new one before deleting it.
Revoking the old one: Delete the old key under Credentials > Key pairs. Private keys do not expire and must be revoked manually.
Source: docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/managing-private-keys-for-github-apps, checked
Does the GitHub App private key expire?
No. The GitHub App private key doesn't expire on its own: it works until you revoke it.
What breaks when the GitHub App private key expires
Private keys do not expire, so there is no expiry failure. A deleted key can no longer be used; the docs read do not give the exact error returned to an app still signing with it.
How to rotate the GitHub deploy key
- Generate a new key pair on the server with ssh-keygen and note where it is saved. Use a dedicated pair for each repository: a deploy key cannot be reused across repositories GitHub docs
- In the repository, open Settings, click Deploy Keys in the sidebar, then Add deploy key. Enter a title, paste the new public key, tick Allow write access only if the deployment needs to push, and click Add key GitHub docs
- Point the server at the new private key and check it works, for example with git clone git@github.com:OWNER/REPO.git GitHub docs
- Remove the old key through the REST API: DELETE /repos/{owner}/{repo}/keys/{key_id} returns 204. Find the key_id with GET /repos/{owner}/{repo}/keys. The managing-deploy-keys page does not document a web UI removal step GitHub docs
Can the old and new key work at the same time? GitHub's docs don't say. The docs do not state a per-repository key limit or whether two deploy keys can be active on one repository at once; each deploy key is a separate entry added to the repository, so a new key can be added before the old one is removed, but the pages read do not say so outright.
Revoking the old one: Delete the old key with DELETE /repos/{owner}/{repo}/keys/{key_id}. A deploy key created with a personal access token is also deleted when that token is deleted.
Source: docs.github.com/en/authentication/connecting-to-github-with-ssh/managing-deploy-keys, checked
Does the GitHub deploy key expire?
No. The GitHub deploy key doesn't expire on its own: it works until you revoke it.
What breaks when the GitHub deploy key expires
Deploy keys have no expiry date in the docs read. The exact git error after a key is removed is not documented there.
Each credential
GitHub account login
- Not documented
Organization owners can enforce policies on tokens and access.
Fine-grained personal access token
- You choose
- Can be scoped
- Expiry readable by API
Expiration is chosen at creation. Docs: infinite lifetimes are allowed but may be blocked by an organization or enterprise maximum-lifetime policy (the org policy page says fine-grained tokens default to a 366-day maximum unless the owner changes it). The docs give no general maximum for the creation form; the URL pre-fill accepts expires_in of 1 to 366 or none, defaulting to 30 days if omitted. Organization owners can read token_expires_at and token_expired through the org personal-access-tokens REST endpoints. Access is scoped per repository and per permission. Tokens unused for a year are removed automatically.
Classic personal access token
- You choose
- Can be scoped
Expiration is optional: the creation steps say to choose a default option or a custom date to give the token an expiration, and GitHub strongly recommends one. Tokens unused for a year are removed automatically. Org owners can set a maximum lifetime for classic tokens too, but by default classic tokens have no expiration requirement. Access uses OAuth-style scopes, less granular than fine-grained tokens.
GitHub App private key (PEM)
- Doesn't expire
- Full access only
Private keys do not expire and must be revoked manually by deleting them. Up to 25 keys per app. Deleting the only key requires creating a new one first. GitHub stores only the public key, so the downloaded PEM cannot be recovered.
Deploy key (SSH)
- Doesn't expire
- Can be scoped
Deploy keys have no expiry date. They are read-only by default and can be given write access when added. Each key grants access to one repository and cannot be reused across repositories. The managing-deploy-keys page has no removal steps; the REST API documents DELETE /repos/{owner}/{repo}/keys/{key_id}. Keys are immutable: to change one, remove it and add a new one.
Renewals and billing
- GitHub Team or Pro plan.
Where to find it in GitHub
- Open GitHub fine-grained tokens
- Open a prefilled fine-grained token (example: contents write, 90 days; replace for each recipe)
- GitHub fine-grained token guide, including URL parameters
What GitHub's docs don't say
We couldn't confirm these from official docs, so don't rely on them either way:
- UI default expiration for fine-grained tokens (30 days is documented only for the URL pre-fill parameter)
- Whether a literal 'No expiration' option exists for classic tokens in the UI
- Classic token expiry presets
- Whether a user (non-org-owner) can read their own token expiry via the API
- Removal steps for deploy keys
- OAuth app client secret lifecycle
- Plan billing cadence and billing/usage APIs
- Whether the Regenerate token button exists and what it keeps (scopes, expiry)
- Expiry notification emails to token owners or org owners
- Exact error git, the API and Actions return for an expired token
- Editing an existing Actions secret in the web UI; gh secret set overwrite behaviour
- How long a removed deploy key or deleted app key takes to stop working
Rotating or replacing a GitHub key
The steps are the same for most providers: make the new key, deploy it everywhere the old one is used, check it works, then revoke the old one. Our guides walk through it:
Sources
- docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens
- docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/managing-private-keys-for-github-apps
- docs.github.com/en/authentication/connecting-to-github-with-ssh/managing-deploy-keys
- docs.github.com/en/organizations/managing-programmatic-access-to-your-organization/setting-a-personal-access-token-policy-for-your-organization
- docs.github.com/en/rest/orgs/personal-access-tokens
- docs.github.com/en/rest/actions/secrets
- docs.github.com/en/rest/overview/permissions-required-for-fine-grained-personal-access-tokens
- docs.github.com/en/organizations/keeping-your-organization-secure/managing-security-settings-for-your-organization/audit-log-events-for-your-organization
- docs.github.com/en/billing/how-tos/manage-plan-and-licenses
- docs.github.com/en/billing/how-tos/manage-plan-and-licenses/downgrade-plan
- docs.github.com/en/actions/security-guides/using-secrets-in-github-actions
- docs.github.com/en/actions/reference/security/secrets
- docs.github.com/en/authentication/keeping-your-account-and-data-secure/token-expiration-and-revocation
- docs.github.com/en/rest/deploy-keys/deploy-keys
Keep track of every GitHub key
StackHangar stores your GitHub keys in an encrypted vault, grouped by the product they belong to, warns you before they expire, and walks you through rotating them. We can't read your secrets.