DEV Community

Steve Coffman
Steve Coffman

Posted on • Updated on

GitHub Actions and checking Tokens for expiration

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
Enter fullscreen mode Exit fullscreen mode

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>'
Enter fullscreen mode Exit fullscreen mode

GitHub Enterprise:

curl -XGET -H 'authorization: token <personal token>' 'https://<GHE url>/api/v3/repos/<owner>/<repo>'
Enter fullscreen mode Exit fullscreen mode

So for instance:

curl -XGET -H 'authorization: token '"${GHBOT_TOKEN}" https://api.github.com/repos/MyOrg/MyRepo
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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/"
Enter fullscreen mode Exit fullscreen mode

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/"
Enter fullscreen mode Exit fullscreen mode

Sometimes when you use:

echo "${{ secrets.MY_SSH_PRIVATE_KEY }}" | ssh-add - > /dev/null
Enter fullscreen mode Exit fullscreen mode

You will sometimes get a failure:

Error loading key "(stdin)": error in libcrypto
Enter fullscreen mode Exit fullscreen mode

You might have some carriage returns in there so try:

echo "${{ secrets.MY_SSH_PRIVATE_KEY }}" | tr -d '\r' | ssh-add - > /dev/null
Enter fullscreen mode Exit fullscreen mode

Also for some reason(?), this appears more reliable:

ssh-add - <<< "${{ secrets.MY_SSH_PRIVATE_KEY }}"
Enter fullscreen mode Exit fullscreen mode
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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Top comments (0)