---
name: "GitHub App Token"
description: "Generate a GitHub App installation access token for Buildkite steps."
author: "tommeier"
repo: "github-app-token-buildkite-plugin"
stars: 0
official: false
version: "v1.0.0"
lastUpdated: "2026-03-30T04:16:39.000Z"
---

# GitHub App Token Buildkite Plugin

Generate a [GitHub App](https://docs.github.com/en/apps) installation access token
and export it as an environment variable for Buildkite steps.

This is the Buildkite equivalent of [actions/create-github-app-token](https://github.com/actions/create-github-app-token).

## How it works

1. Reads the App ID, private key, and installation ID from Buildkite secrets
2. Signs a JWT (RS256) using the private key
3. Exchanges the JWT for an installation access token via the GitHub API
4. Exports the token as `GH_TOKEN` (or a configured variable name)

The token is valid for one hour and has the permissions granted to the GitHub App
installation.

## Example

```yml
steps:
  - label: ":github: Create Release"
    plugins:
      - github-app-token#v1.0.0: ~
    command: gh release create v1.0.0 --generate-notes
```

This requires three Buildkite secrets: `GITHUB_APP_ID`, `GITHUB_APP_PRIVATE_KEY`,
and `GITHUB_APP_INSTALLATION_ID`. The `gh` CLI automatically uses the exported
`GH_TOKEN`.

## Custom Secret Names

If your secrets use different env var names:

```yml
plugins:
  - github-app-token#v1.0.0:
      app-id-env: MY_GITHUB_APP_ID
      private-key-env: MY_GITHUB_APP_KEY
      installation-id-env: MY_GITHUB_APP_INSTALL_ID
```

## GitHub Enterprise Server

```yml
plugins:
  - github-app-token#v1.0.0:
      api-url: https://github.example.com/api/v3
```

## Configuration

| Option | Default | Description |
|--------|---------|-------------|
| `app-id-env` | `GITHUB_APP_ID` | Env var containing the GitHub App ID |
| `private-key-env` | `GITHUB_APP_PRIVATE_KEY` | Env var containing the PEM private key |
| `installation-id-env` | `GITHUB_APP_INSTALLATION_ID` | Env var containing the installation ID |
| `token-variable` | `GH_TOKEN` | Env var name to export the token as |
| `api-url` | `https://api.github.com` | GitHub API base URL |
| `hook` | `environment` | Which hook to run in: `environment` or `pre-command` |

Config values are **env var names**, not secrets themselves — secrets never appear in
pipeline YAML.

## Requirements

- `bash`
- `curl`
- `openssl`
- `jq`

All four are available on Buildkite hosted agents and most CI environments.

## Secrets Setup

1. [Create a GitHub App](https://docs.github.com/en/apps/creating-github-apps) with
   the permissions your pipeline needs
2. Install the app on your organization or repository
3. Note the **App ID** (from the app's settings page) and **Installation ID** (from
   the URL after installing: `https://github.com/settings/installations/<ID>`)
4. Generate a private key (PEM format) from the app's settings page
5. Add all three as [Buildkite secrets](https://buildkite.com/docs/pipelines/security/secrets/managing):

```bash
bk secret set GITHUB_APP_ID "12345"
bk secret set GITHUB_APP_PRIVATE_KEY "$(cat private-key.pem)"
bk secret set GITHUB_APP_INSTALLATION_ID "67890"
```

## Why GitHub Apps over Personal Access Tokens?

- **Not tied to a human** — Apps are their own identity; no single point of failure
- **Fine-grained permissions** — Request only what the pipeline needs
- **Higher rate limits** — 5,000 requests/hour per installation vs 5,000/hour per user
- **Automatic expiry** — Installation tokens expire after 1 hour; PATs can live forever
- **Audit trail** — Actions are attributed to the app, not a person

## Development

```bash
bats tests/plugin.bats
docker run --rm -v "$PWD:/plugin" -w /plugin buildkite/plugin-linter --id tommeier/github-app-token --path /plugin
shellcheck hooks/* lib/*.bash
```