How to use gh auth login CLI Programmatically in GitHub Actions
Using the gh cli to programmatically authenticate in GitHub Actions
Overview
Quick post here since I have to search for this every time I try to use the gh cli
in GitHub Actions. In order to use the gh cli
, you typically have to run gh auth login
to authenticate. If you are running this from an interactive session (ie: on your local machine), you are provided with some prompts to easily authenticate to GitHub.com or GitHub Enterprise Server. If you try to do this from an command in a GitHub Actions, the action will just stall out and you will have to cancel since gh auth login
is intended to be done in an interactive session.
There is a gh auth login --with-token
in the docs that provides an example for reading from a file, but if you’re running in a GitHub Action workflow, your ${{ secrets.GITHUB_TOKEN }}
isn’t going to be a file.
Example 1 - gh auth login
Here’s an example GitHub Action sample for logging into the gh cli
and using gh api
to retrieve a repositories topics:
1
2
3
4
steps:
- run: |
echo ${{ secrets.GITHUB_TOKEN }} | gh auth login --with-token
gh api -X GET /repos/${{ GITHUB.REPOSITORY }}/topics --jq='.names'
This works, but there’s a better way that doesn’t require running a gh auth login
command at all.
Example 2 - env variable
✨ If you try to run a gh
command without authenticating, you will see the following error message:
gh: To use GitHub CLI in a GitHub Actions workflow, set the GH_TOKEN environment variable. Example:
1 2 env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
With this, you will notice you don’t have to run gh auth login
at all. You can just set the GH_TOKEN
environment variable to the value of ${{ secrets.GITHUB_TOKEN }}
and the gh cli
will use that token to authenticate. You can set the environment variable at the workflow level, job level, or step level.
This is an example of the least privilege approach, setting the env
variable at the step level, and allowing different steps to use different tokens if needed:
1
2
3
4
steps:
- run: gh issue create --title "My new issue" --body "Here are more details."
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
If you are using gh cli
in multiple steps or jobs in a workflow, setting the GH_TOKEN
as a workflow (or https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#env) level, job [env
] variable might be more efficient:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} # setting GH_TOKEN for the entire workflow
jobs:
prebuild:
runs-on: ubuntu-latest
# env:
# GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} # setting GH_TOKEN for the entire job
steps:
- run: |
gh api -X GET /repos/${{ GITHUB.REPOSITORY }}/topics --jq='.names'
build:
runs-on: ubuntu-latest
steps:
- run: |
gh api -X GET /repos/${{ GITHUB.REPOSITORY }}/branches --jq='.[].name'
Example 3 - Authenticate with GitHub App
This example combines concepts learned in this post with the Demystifying GitHub Apps: Using GitHub Apps to Replace Service Accounts post.
You may want to use a GitHub app to authenticate and use the gh cli
in a GitHub Action workflow to do something. You can manage permissions more with the GitHub App, and installing it on the org / granting access to multiple repositories whereas ${{ secrets.GITHUB_TOKEN }}
only has access to resources inside of the repository running the action. In addition, you can give the actor a more meaningful name (e.g.: PR-Enforcer-Bot
) vs. the default github-actions[bot]
user.
Here’s an example that uses an app to create an issue in a different repository:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
steps:
- uses: actions/create-github-app-token@v1
id: app-token
with:
app-id: ${{ vars.APP_ID }}
private-key: ${{ secrets.PRIVATE_KEY }}
# optional: owner not needed IF the app has access to the repo running the workflow
# if you get 'RequestError [HttpError]: Not Found 404', pass in owner
owner: ${{ github.repository_owner }}
- name: Create Issue
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
run: |
gh issue create --title "My new issue" --body "Here are more details." \
-R my-org/my-repo