askvity

How to Set Permissions on GitHub Workflow

Published in GitHub Actions Permissions 5 mins read

You can set permissions on a GitHub workflow by specifying the permissions key either at the top level of your workflow file or within individual jobs. This controls the access level granted to the GITHUB_TOKEN.

Why Set Permissions?

GitHub Actions workflows automatically generate a unique GITHUB_TOKEN for each job run. This token is used to authenticate requests made to the GitHub API on behalf of your repository. By default, this token has a limited set of permissions. Setting permissions explicitly allows you to:

  • Increase permissions for specific tasks that require broader access (e.g., creating releases, adding comments).
  • Decrease permissions to follow the principle of least privilege, enhancing security by restricting what the workflow token can do.

Where to Set Permissions

As stated in the documentation, you can use permissions either as a top-level key, to apply to all jobs in the workflow, or within specific jobs.

1. Top-Level Workflow Permissions

Setting permissions at the top level applies those access rights as the default for all jobs within that workflow. This is useful when most jobs require a similar set of permissions.

# .github/workflows/my-workflow.yml
name: My Workflow

permissions:
  contents: read # Default permission for all jobs is read-only for contents

on: [push]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4 # Uses the default 'contents: read' permission

  deploy:
    runs-on: ubuntu-latest
    # This job also inherits 'contents: read' but needs write access for releases
    permissions:
      contents: write # Overrides the workflow-level permission for THIS job
    steps:
      - name: Create Release
        # This step would need write permission for contents
        # ... steps to create release ...

In this example, contents: read is the default for both the build and deploy jobs. However, the deploy job specifically overrides the contents permission to write, allowing it to perform actions like creating releases.

2. Job-Level Permissions

Setting permissions within a specific job applies those access rights only to that particular job. When you add the permissions key within a specific job, all actions and run commands within that job that use the GITHUB_TOKEN gain the access rights you specify. This overrides any permissions set at the workflow level for that specific job. This is ideal when only one job requires elevated or reduced permissions.

# .github/workflows/another-workflow.yml
name: Another Workflow

# No top-level permissions defined - uses default permissions

on: [push]

jobs:
  lint:
    runs-on: ubuntu-latest
    # No permissions key here - uses default GITHUB_TOKEN permissions
    steps:
      - name: Run Linter
        # ... linter steps ...

  comment:
    runs-on: ubuntu-latest
    permissions:
      issues: write # Only this job gets write access for issues
    steps:
      - name: Add Issue Comment
        # This step can add comments to issues using the token
        # ... steps to add comment ...

In this workflow, the lint job uses the default GITHUB_TOKEN permissions (which are typically read-only for most scopes). The comment job, however, is granted explicit write permission for issues, allowing it to interact with issues via the API.

Understanding Permission Scopes and Levels

Permissions are set using key-value pairs where the key is the scope (e.g., contents, issues, pull-requests) and the value is the access level (read, write, or none).

Here are some common scopes and their purposes:

Scope Description Access Levels
actions Manage GitHub Actions workflow runs. read, write, none
contents Manage repository contents, commits, tags. read, write, none
deployments Manage deployments. read, write, none
issues Manage issues and issue comments. read, write, none
pull-requests Manage pull requests and PR comments. read, write, none
packages Manage GitHub Packages. read, write, none
statuses Manage commit statuses. read, write, none
checks Manage checks. read, write, none
discussions Manage repository discussions. read, write, none
id-token Request an OIDC ID token. write, none
metadata Always read-only; required by actions/checkout. read (default)

You can set permissions for multiple scopes:

permissions:
  contents: read
  issues: write
  pull-requests: write

Best Practices

  • Least Privilege: Grant only the permissions absolutely necessary for the job or workflow to complete its tasks.
  • Job-Level Specificity: Use job-level permissions when only one job needs specific access, overriding the workflow-level defaults.
  • Review Defaults: Understand the default permissions your repository settings apply to the GITHUB_TOKEN. You can often reduce overall permissions at the repository or organization level for increased security.

By strategically using the permissions key at the workflow or job level, you can precisely control the GITHUB_TOKEN's capabilities, balancing functionality with security.

Related Articles