Why a GitHub App Token Beats a Personal Access Token in CI
A GitHub App installation token is scoped to chosen repos, expires in an hour, and belongs to the org, not a person.
A personal access token inherits a user's access and lives for months. A GitHub App installation token is minted per run, scoped to the repos the App is installed on, and revoked automatically when it expires, which shrinks the blast radius if it leaks.
How they differ
| Property | User PAT | App installation token |
|---|---|---|
| Owner | A person | The App / org |
| Lifetime | Days to no expiry | ~1 hour, auto-revoked |
| Scope | All the user can see | Only installed repos + granted permissions |
| Rate limit | 5,000 req/hour (user) | Scales with installation size |
| Offboarding risk | Breaks when user leaves | Unaffected by staff changes |
Mint one in a workflow
.github/workflows/ci.yml
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/create-github-app-token@v1
id: app-token
with:
app-id: ${{ vars.APP_ID }}
private-key: ${{ secrets.APP_PRIVATE_KEY }}
- uses: actions/checkout@v4
with:
token: ${{ steps.app-token.outputs.token }}When a PAT is still fine
- A throwaway one-off script where setting up an App is overkill.
- A fine-grained PAT scoped to a single repo with a short expiry is a reasonable middle ground.
- Prefer short-lived scoped tokens over long-lived PATs whenever the token touches other repos.
Related guides
How to Generate a GitHub App Installation Token in a WorkflowGenerate a short-lived GitHub App installation access token inside GitHub Actions with actions/create-github-…
How to Choose Between Fine-Grained PAT, Classic PAT, and GitHub AppDecide between a fine-grained personal access token, a classic PAT, and a GitHub App installation token for C…