What is a GitHub token?
GitHub lets you create a Personal Access Token (PAT) for your GitHub user. These types of tokens are used pretty much the same as the GitHub Action default token.
A GitHub Action default GITHUB_TOKEN
expires when a job finishes or after a maximum of 24 hours.
Your GitHub Personal Access Token (PAT) may expire when it's past its expiration date, but GitHub may also expire or revoke it for a variety of other reasons. It is pretty tedious to tell which if any of those other reasons have happened.
In either case, both the official GitHub Actions (like checkout) and the marketplace ones will often fail with a very unhelpful error:
Error: fatal: could not read Username for 'https://github.com': terminal prompts disabled
The layers of their JavaScript between you and a git
command will never be updated to make more friendly error messages upon failure.
Instead, if you add a step to your own workflow you can emit helpful action items for when these errors occur and save your future self from wasting time.
Verify GitHub Token has access (and is not expired)
You can verify your Personal Access Token is not expired and has proper permissions:
GitHub:
curl -XGET -H 'authorization: token <personal token>' '<https://api.github.com/repos/><owner>/<repo>'
GitHub Enterprise:
curl -XGET -H 'authorization: token <personal token>' 'https://<GHE url>/api/v3/repos/<owner>/<repo>'
So for instance:
curl -XGET -H 'authorization: token '"${GHBOT_TOKEN}" https://api.github.com/repos/MyOrg/MyRepo
So write a quick script to use as a step in your workflow:
echo "Checking GitHub Token for expiry and/or access"
# prepend some arguments, but pass on whatever arguments this script was called with
output="$(curl -XGET \
--write '\n%{http_code}\n' \
--silent \
--fail -H 'Content-Type:application/json' \
-H 'Accept:application/json' \
-H 'authorization: token '"${GHBOT_TOKEN}" https://api.github.com/repos/MyOrg/MyRepo \
)"
return_code=$?
if [ 0 -eq $return_code ]; then
# remove the "http_code" line from the end of the output, and parse it
echo "Yay! Your personal access code is not expired and has access to this repo"
else
echo "Boo! Your personal access code is expired or has no access"
# comment the next line if you don't want to see the HTTP status code and return messages from GitHub
echo "Failure: code=$output"
exit 1
fi
So you can put this in your GitHub Action workflow:
steps:
- name: Check Personal Access Token
run: |
echo "Checking GitHub Token for expiry and/or access"
# prepend some arguments, but pass on whatever arguments this script was called with
output="$(curl -XGET \
--write '\n%{http_code}\n' \
--silent \
--fail -H 'Content-Type:application/json' \
-H 'Accept:application/json' \
-H 'authorization: token '"${GHBOT_TOKEN}" https://api.github.com/repos/MyOrg/MyRepo \
)"
return_code=$?
if [ 0 -eq $return_code ]; then
# remove the "http_code" line from the end of the output, and parse it
echo "Yay! Your personal access code is not expired and has access to this repo"
else
echo "Boo! Your personal access code is expired or has no access"
# comment the next line if you don't want to see the HTTP status code and return messages from GitHub
echo "Failure: code=$output"
exit 1
fi
If you are using the default GitHub token, change the above ${GHBOT_TOKEN}
(which is sourced by from a shell environment variable you set in your action) to instead be ${{ secrets.GITHUB_TOKEN }}
which the action will replace before it passes the script to the shell.
Or write your own layers of JavaScript to check if the token is expired. You do you.
Bonus content
Setting your git config to use a the token in a GitHub action can be done with the token:
- name: Setup git config via HTTPS using token
run: |
echo "Configuring git for HTTPS using token"
git config --global user.name "github-actions[bot]"
git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
git config --global url."https://oauth2:${{ secrets.GITHUB_TOKEN }}@github.com/".insteadOf "https://github.com/"
Or you can decide this whole token/HTTPS thing is dumb and use SSH keys (like a deploy key). Warning: GitHub will mark any commits as being authored by the same user who created the deploy key:
name: My cool workflow
env:
SSH_AUTH_SOCK: /tmp/ssh_agent.sock
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
jobs:
cooljobnamehere:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Setup Git with SSH Keys and known_hosts
run: |
ssh-agent -a "${SSH_AUTH_SOCK}" > /dev/null
ssh-add - <<< "${{ secrets.MY_SSH_PRIVATE_KEY }}"
echo "Configuring git..."
git config --global user.name "github-actions[bot]"
git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
git config --global url."git@github.com:".insteadOf "https://github.com/"
Sometimes when you use:
echo "${{ secrets.MY_SSH_PRIVATE_KEY }}" | ssh-add - > /dev/null
You will sometimes get a failure:
Error loading key "(stdin)": error in libcrypto
You might have some carriage returns in there so try:
echo "${{ secrets.MY_SSH_PRIVATE_KEY }}" | tr -d '\r' | ssh-add - > /dev/null
Also for some reason(?), this appears more reliable:
ssh-add - <<< "${{ secrets.MY_SSH_PRIVATE_KEY }}"
Testing your SSH Deploy Key
You likely have your own developer SSH config and key, but if you want to verify an SSH Deploy key (or a bot GitHub account SSH key):
ssh -F /dev/null -o"IdentitiesOnly=yes" -o"StrictHostKeyChecking=no" -i id_ed25519 -T git@github.com
Just ensure that the key and its directory have proper permissions!
Typically you want the permissions to be:
Item | Sample | Numeric | Bitwise |
---|---|---|---|
SSH folder | ~/.ssh |
700 |
drwx------ |
Public key | ~/.ssh/id_rsa.pub |
644 |
-rw-r--r-- |
Private key | ~/.ssh/id_rsa |
600 |
-rw------- |
Home folder | ~ |
755 |
drwxr-xr-x |
So when you are in the deploy key directory:
chmod 700 .
chmod 600 id_ed25519
chmod 600 id_ed25519.pub
Top comments (0)