# GitHub App
The `github-app` lease backend creates short-lived [GitHub App installation access tokens](https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/generating-an-installation-access-token-for-a-github-app) using a GitHub App's private key. Installation tokens expire after 1 hour (GitHub's hard limit) and can be scoped to specific permissions and repositories.
This is ideal for CI/CD pipelines and automation workflows where you need scoped, short-lived GitHub access instead of long-lived personal access tokens.
:::tip Prefer GitHub OAuth for local workflows
If you want a short-lived token for local development or user-attributed GitHub CLI/API usage, consider [`github-oauth`](/leases/github-oauth) instead. It only requires the GitHub App client ID, so you do not need to distribute or manage an app private key.
:::
## Configuration
```toml
[leases.github]
type = "github-app"
app_id = "12345"
installation_id = "67890"
private_key_file = "~/.config/fnox/github-app.pem"
duration = "1h"
[leases.github.permissions]
contents = "read"
pull_requests = "write"
```
| `app_id` | Yes | GitHub App ID (found in the app's settings page) |
| `installation_id` | Yes | Installation ID (from the app's installation URL or API) |
| `private_key_file` | No\* | Path to the GitHub App's PEM private key file (supports `~` expansion) |
| `env_var` | No | Environment variable name for the token (default: `"GITHUB_TOKEN"`) |
| `permissions` | No | Map of permission names to access levels (omit to use all installation permissions) |
| `repositories` | No | Array of bare repository names to scope the token to (omit for all installed repos) |
| `api_base` | No | GitHub API base URL (default: `"https://api.github.com"`; set for GitHub Enterprise) |
| `duration` | No | Ignored — GitHub controls token lifetime (always 1 hour) |
\* Required unless `FNOX_GITHUB_APP_PRIVATE_KEY` is set.
### Permission values
Permissions use GitHub's [installation token permission names](https://docs.github.com/en/rest/apps/apps#create-an-installation-access-token-for-an-app). Each permission maps to an access level:
| `"read"` | Read-only access |
| `"write"` | Read and write |
| `"admin"` | Full administrative |
## Prerequisites
The backend needs a GitHub App private key. fnox looks for it in order:
1. `FNOX_GITHUB_APP_PRIVATE_KEY` environment variable (PEM contents)
2. `private_key_file` config option (path to PEM file)
If neither is found, fnox prints:
```
GitHub App private key not found. Set FNOX_GITHUB_APP_PRIVATE_KEY or configure private_key_file pointing to a PEM file.
```
### Getting the app ID and installation ID
1. **App ID**: Go to your GitHub App's settings page (`Settings > Developer settings > GitHub Apps > Your App`). The App ID is shown near the top.
2. **Installation ID**: After installing the app on an organization or account, the installation ID is in the URL: `https://github.com/settings/installations/{installation_id}`. You can also find it via the API:
```bash
# List installations for your app (requires JWT auth)
curl -H "Authorization: Bearer $JWT" \
https://api.github.com/app/installations
```
### Generating a private key
In your GitHub App settings, scroll to "Private keys" and click "Generate a private key". Save the downloaded PEM file to a secure location.
## Credentials Produced
| `GITHUB_TOKEN` | Short-lived installation access token |
The env var name is configurable via the `env_var` field.
## Limits
- **Max duration:** 1 hour (enforced by GitHub)
- **Revocation:** Supported — fnox calls `DELETE /installation/token` to immediately invalidate the token
## Examples
### Minimal
```toml
[leases.github]
type = "github-app"
app_id = "12345"
installation_id = "67890"
private_key_file = "~/.config/fnox/github-app.pem"
```
The token gets all permissions and repository access granted to the installation.
```bash
fnox exec -- gh pr list
```
### Scoped to specific permissions
```toml
[leases.github]
type = "github-app"
app_id = "12345"
installation_id = "67890"
private_key_file = "~/.config/fnox/github-app.pem"
[leases.github.permissions]
contents = "read"
pull_requests = "write"
issues = "write"
```
### Scoped to specific repositories
```toml
[leases.github]
type = "github-app"
app_id = "12345"
installation_id = "67890"
private_key_file = "~/.config/fnox/github-app.pem"
repositories = ["api", "frontend"]
[leases.github.permissions]
contents = "read"
```
### With stored private key
Instead of a file, store the private key in a provider:
```toml
[providers.op]
type = "1password"
vault = "Infrastructure"
[secrets]
FNOX_GITHUB_APP_PRIVATE_KEY = { provider = "op", value = "GitHub App/private key" }
[leases.github]
type = "github-app"
app_id = "12345"
installation_id = "67890"
```
fnox resolves the secret first, then the lease backend picks it up from the environment.
### Custom env var
```toml
[leases.github]
type = "github-app"
app_id = "12345"
installation_id = "67890"
private_key_file = "~/.config/fnox/github-app.pem"
env_var = "GH_TOKEN"
```
### GitHub Enterprise
```toml
[leases.github]
type = "github-app"
app_id = "12345"
installation_id = "67890"
private_key_file = "~/.config/fnox/github-app.pem"
api_base = "https://github.example.com/api/v3"
```
### Common permissions
| `contents` | Repository contents, commits, branches |
| `pull_requests` | Pull requests |
| `issues` | Issues and comments |
| `actions` | GitHub Actions workflows |
| `packages` | GitHub Packages |
| `deployments` | Deployment statuses |
| `environments` | Deployment environments |
| `metadata` | Repository metadata (always read-only) |
| `administration` | Repository settings |
| `members` | Organization members |
| `organization_plan` | Organization billing info |
See the [GitHub API docs](https://docs.github.com/en/rest/apps/apps#create-an-installation-access-token-for-an-app) for the full list.
## See Also
- [Credential Leases](/guide/leases) — overview and approaches