Files
skills/github-app-token/SKILL.md
T
Goose 39b1d0abc2 feat: write github-app-token to per-agent file instead of env var
Replaces `export GH_TOKEN` with a file-based approach using
`$AGENT_HOME/.gh-token`. Each agent writes its token to its own
file path, avoiding env-var collisions when multiple agents
generate tokens concurrently.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-01 11:07:53 +00:00

3.1 KiB

name, description
name description
github-app-token Generate a GitHub installation access token from a GitHub App PEM key, App ID, and Installation ID, write it to a per-agent file, then authenticate the gh CLI with it.

GitHub App Token Skill

Generate a short-lived GitHub installation access token from a GitHub App's credentials and use it to authenticate the gh CLI.

Prerequisites

The following environment variables MUST be set before invoking this skill:

Variable Description
GITHUB_APP_ID The numeric App ID from the GitHub App settings page
GITHUB_APP_INSTALLATION_ID The numeric Installation ID for the target org/user
GITHUB_APP_PEM_FILE Absolute path to the GitHub App's PEM private key file

If any variable is missing, stop and tell the user which ones are required.

Requires openssl, curl, and jq.

Generate a Token

Build a JWT signed with the App's private key, then exchange it for an installation access token and write it to a file:

# Base64url helper
b64enc() { openssl enc -base64 -A | tr '+/' '-_' | tr -d '='; }

# Build JWT (valid 10 minutes)
NOW=$(date +%s)
HEADER=$(printf '{"alg":"RS256","typ":"JWT"}' | jq -r -c .)
PAYLOAD=$(printf '{"iat":%s,"exp":%s,"iss":"%s"}' "$NOW" "$((NOW + 600))" "$GITHUB_APP_ID" | jq -r -c .)
SIGNED=$(printf '%s' "$HEADER" | b64enc).$(printf '%s' "$PAYLOAD" | b64enc)
SIG=$(printf '%s' "$SIGNED" | openssl dgst -binary -sha256 -sign "$GITHUB_APP_PEM_FILE" | b64enc)
JWT="${SIGNED}.${SIG}"

# Token file — unique per agent to avoid env-var collisions
GH_TOKEN_FILE="${AGENT_HOME:+${AGENT_HOME}/.gh-token}"
GH_TOKEN_FILE="${GH_TOKEN_FILE:-$(mktemp)}"

# Exchange JWT for installation token and write to file
curl -s -X POST \
  -H "Authorization: Bearer ${JWT}" \
  -H "Accept: application/vnd.github+json" \
  -H "X-GitHub-Api-Version: 2022-11-28" \
  "https://api.github.com/app/installations/${GITHUB_APP_INSTALLATION_ID}/access_tokens" \
  | jq -r '.token' > "$GH_TOKEN_FILE"

chmod 600 "$GH_TOKEN_FILE"

The token file path defaults to $AGENT_HOME/.gh-token (unique per agent) or a temporary file when AGENT_HOME is not set. This avoids env-var collisions when multiple agents generate tokens concurrently.

Authenticate the gh CLI

Read the token from the file and log in:

gh auth login --with-token < "$GH_TOKEN_FILE"

To use GH_TOKEN in a single command without polluting the environment:

GH_TOKEN=$(cat "$GH_TOKEN_FILE") gh api user

Cleanup

The installation access token expires after 1 hour. To revoke it early and remove the token file:

curl -s -X DELETE \
  -H "Authorization: Bearer $(cat "$GH_TOKEN_FILE")" \
  -H "Accept: application/vnd.github+json" \
  "https://api.github.com/installation/token"
rm -f "$GH_TOKEN_FILE"

Security Notes

  • Never log or echo the PEM key or installation token to stdout in production.
  • The installation token is valid for 1 hour from generation.
  • Store the PEM file with restrictive permissions (chmod 600) and never check it into git.
  • The token file is written with mode 600 and should be cleaned up after use.