GitHub Actions Tutorial — GITHUB_TOKEN

2 minute read

GITHUB_TOKEN

Every workflow run automatically receives a GITHUB_TOKEN — a short-lived token that authenticates with the GitHub API. You don’t need to create or store it; GitHub manages it for you.


How It Works

Workflow starts
    ↓
GitHub generates GITHUB_TOKEN
    ↓
Token scoped to the repository
    ↓
Available as: secrets.GITHUB_TOKEN
    ↓
Workflow ends → token expires

Accessing the Token


steps:
  - name: Use token
    env:
      GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
    run: |
      gh api repos/${{ github.repository }}

Or pass it to an action:


steps:
  - uses: actions/checkout@v4
    with:
      token: ${{ secrets.GITHUB_TOKEN }}


Default Permissions

The token’s default permissions depend on your repository settings (Settings → Actions → General → Workflow permissions):

Setting Read Write
Read and write (default for older repos) ✅ All ✅ All
Read-only (recommended) ✅ Contents, metadata ❌

Best practice: Set default to read-only and grant specific permissions per workflow.


Setting Permissions in the Workflow


permissions:
  contents: read          # read repo contents
  pull-requests: write    # comment on PRs
  issues: write           # create/edit issues

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Comment on PR
        if: github.event_name == 'pull_request'
        uses: actions/github-script@v7
        with:
          script: |
            github.rest.issues.createComment({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: context.issue.number,
              body: '✅ Build passed!'
            })

Available Permission Scopes

Scope Read Write
contents Clone, read files Push commits, create releases
pull-requests Read PRs Comment, review, merge
issues Read issues Create, comment, label
packages Download packages Publish packages
deployments Read deployments Create deployments
statuses Read commit statuses Create commit statuses
actions Read workflow runs Cancel/re-run workflows
id-token — Request OIDC token

Permission at Job Level


jobs:
  read-job:
    runs-on: ubuntu-latest
    permissions:
      contents: read
    steps:
      - uses: actions/checkout@v4

  write-job:
    runs-on: ubuntu-latest
    permissions:
      contents: write
      packages: write
    steps:
      - run: echo "This job can push"


GITHUB_TOKEN Limitations

Limitation Alternative
Can’t trigger other workflows Use a Personal Access Token (PAT)
Can’t access other repos Use a PAT or GitHub App token
Can’t push to protected branches Use a PAT with admin scope
Expires when workflow ends Use PAT for long-lived needs

Why It Can’t Trigger Workflows

To prevent infinite loops, pushes made with GITHUB_TOKEN don’t trigger new workflow runs:


steps:
  # This push won't trigger another workflow
  - run: |
      git commit --allow-empty -m "trigger"
      git push
    env:
      GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

To trigger another workflow, use a PAT or GitHub App token.


Common Mistakes

Mistake Fix
403 Forbidden when using token Add required permissions: to the workflow
Push doesn’t trigger next workflow Use a PAT instead of GITHUB_TOKEN
Token doesn’t work for other repos GITHUB_TOKEN is scoped to current repo only
Token expired GITHUB_TOKEN is valid for the workflow run duration only

Quick Reference

Concept Detail
Access ${{ secrets.GITHUB_TOKEN }} or ${{ github.token }}
Lifetime Duration of the workflow run
Scope Current repository only
Default Set in repo Settings → Actions
Override permissions: in workflow YAML
Can’t do Trigger workflows, access other repos

← Previous: Secrets

Next: Environments →

Updated: