A GITHUB_TOKEN expires when the job finishes or at its maximum lifetime, whichever comes first. On GitHub-hosted runners that maximum is six hours. On self-hosted runners it can be refreshed for up to 24 hours. Long jobs should not swap it for a long-lived personal token without thinking through the risk.
What GitHub documents
GitHub's concept page on the token says three things relevant here.
- Before each job begins, GitHub fetches an installation access token for the job. Each job gets its own.
- The token's permissions are limited to the repository that contains the workflow.
- It expires when the job finishes or after its effective maximum lifetime. For GitHub-hosted runners the maximum is six hours. For self-hosted runners it can be refreshed for up to 24 hours. For jobs that run longer, GitHub recommends a personal access token or another authentication method.
Why short life is a security feature
A token that dies with the job is a poor prize for an attacker. If an action leaks it into a log or sends it out, the value is useless once the job ends. Compare that with a personal access token or a stored key, which can live for months and often carries more access than any single job needs.
That is the strongest argument for keeping the built in token wherever it is enough, and for limiting its permissions with the permissions key. See GitHub Actions token permissions and least privilege.
What to do when a job outlasts the token
| Situation | Better approach |
|---|---|
| A single step is slow, such as a large test suite | Split the job so the step that needs the token runs in a short job |
| A pipeline waits for human approval | Use environments and separate jobs, so the job that needs access starts after approval |
| A long job must call the API near the end | Fetch a fresh credential at that point, from a short-lived source |
| A long job needs repository write at the end | Hand artifacts to a short final job that has the token |
The common thread is to avoid carrying one credential across a long span. Break the work into jobs, each with its own token and its own permissions.
If you must use another credential
GitHub recommends a personal access token or another authentication method for jobs that run past the limit. If you go that way, narrow it as far as you can.
- Prefer a token from a GitHub App over a personal one, because it is not tied to a person and can be scoped to chosen repositories. See GITHUB_TOKEN vs GitHub App token vs PAT.
- Give it the fewest permissions and the fewest repositories.
- Set a short expiry and rotate it.
- Store it as an environment secret behind approval, not as a repository secret every workflow can read.
- Use it only in the step that needs it.
Cloud credentials follow the same logic
For cloud access, OIDC gives you a short-lived credential per job instead of a stored key. If a job exceeds the credential's lifetime, request a new one at the point of use rather than extending the first. See GitHub Actions OIDC to replace long-lived cloud secrets.
Quick check
Is the six hour figure also the job time limit?
Not necessarily. The six hours is the documented maximum lifetime of the token on GitHub-hosted runners. Check the current job limits in GitHub's documentation for your plan and runner type.
Should I replace GITHUB_TOKEN with a PAT to be safe?
No. A personal token usually lasts longer and carries more access. Keep the built in token unless a job genuinely outlasts it.
Sources
Last reviewed: 19 October 2026.