---
title: GitHub Apps in Canopy
tag: github-apps
summary: >-
  Connect a GitHub App to Canopy, subscribe to events, and unlock GitHub
  workflow and AI Agent actions.
---

# GitHub Apps in Canopy

Canopy supports GitHub App installations and ordinary GitHub OAuth users. This guide focuses on App setup, webhooks, and event workflows, while identifying the separate OAuth setup.

## Three things to understand

A **GitHub App registration** is the App's identity: its name, IDs, private key, permissions, and webhook settings. An **installation** grants that App access to selected repositories in a personal account or organization. A **Canopy connection** points to that installation so workflows know which GitHub account and repositories to use.

`github` is a GitHub App installation connection. `github_oauth` is an ordinary GitHub OAuth user connection. App installations provide repository-scoped permissions and webhook deliveries; OAuth connections authorize the user and request exactly `repo` or `public_repo`. Do not paste a PAT into either connection type.

## Where to create the App

For a personal account, open **GitHub → Settings → Developer settings → GitHub Apps → New GitHub App**: <https://github.com/settings/apps>.

For an organization-owned App, open that organization's **Settings → Developer settings → GitHub Apps**. The direct URL is usually `https://github.com/organizations/<organization>/settings/apps`; you may need organization-owner or administrator access.

Canopy supports independent environment defaults and separate custom App entries in **Settings → Custom Apps** for GitHub App and GitHub OAuth. Use an environment default when one registration serves the deployment; use a custom entry when a workspace needs its own registration.

## Configure the GitHub App

`${APP_URL}` means the Canopy backend origin. `${FRONTEND_URL}` means the visible Canopy application origin. Prefer the URLs that Canopy displays in **Settings** when they are available.

### 1. Register the App in GitHub

Create the App in the personal account or organization where it should live. Set its homepage to `${FRONTEND_URL}` if GitHub asks for one. Set the App user authorization callback to `${APP_URL}/api/oauth/connections/github/callback` and Setup URL to `${APP_URL}/api/oauth/connections/github/setup/callback`.

Enable **Setup URL** and leave **Request user authorization (OAuth) during installation** off.

Choose the minimum permissions for the workflows you plan to run. Create and download the private key PEM, then record the App ID, client ID, client secret, and App slug. Custom-App private keys and secrets are write-only in Canopy.

### 2. Choose and configure the App source

**Environment-default source:** the deployment operator supplies the values below and restarts or redeploys Canopy:

```bash
GITHUB_APP_CLIENT_ID=<github-app-client-id>
GITHUB_APP_CLIENT_SECRET=<github-app-client-secret>
GITHUB_APP_ID=<numeric-github-app-id>
GITHUB_APP_SLUG=<github-app-slug>
GITHUB_APP_PRIVATE_KEY_PATH=<path-to-private-key-pem>
GITHUB_APP_WEBHOOK_SECRET=<github-app-webhook-secret>
```

After Canopy is running, configure the GitHub App webhook: set **Webhook URL** to `${APP_URL}/api/webhooks/github/default`, set **Webhook secret** to the same value as `GITHUB_APP_WEBHOOK_SECRET`, subscribe to the required events, turn **Active** on, and keep SSL verification enabled.

**Workspace custom source:** leave the GitHub webhook inactive while the source is being created. Generate a webhook secret with `openssl rand -hex 32`. Open **Settings → Custom Apps** and save the App ID, slug, client ID, client secret, private key PEM, Permissions JSON, and webhook secret. These secret fields are write-only. Canopy then displays the custom webhook callback; copy it back to GitHub as the **Webhook URL**, enter the same **Webhook secret**, subscribe to the required events, turn **Active** on, and keep SSL verification enabled.

Saving the custom source before its callback exists is expected. GitHub's webhook form has **Active**, **Webhook URL**, **Webhook secret**, and SSL verification; it has no content-type control. GitHub allows one webhook URL per App registration, so use separate App registrations for deployments or workspaces that need different callbacks.

### Ordinary GitHub OAuth

In **Settings → Custom Apps**, create or select the separate GitHub OAuth custom App entry and register `${APP_URL}/api/oauth/connections/github_oauth/callback` in GitHub. Its independent environment default uses:

```bash
GITHUB_OAUTH_CLIENT_ID=<github-oauth-client-id>
GITHUB_OAUTH_CLIENT_SECRET=<github-oauth-client-secret>
GITHUB_OAUTH_REPOSITORY_SCOPE=repo|public_repo
```

OAuth connections authorize an ordinary GitHub user and request exactly the configured `repo` or `public_repo` scope. They support shared GitHub nodes and AI tools, but not event triggers or App webhooks.

Operations targeting a specific repository accept an optional owner. A trimmed explicit owner wins; otherwise App connections use the installation account login and OAuth connections use the verified user login. Repository listing (`list_repos` / `github_list_repositories`) does not accept owner; it uses `/installation/repositories` for `github` and `/user/repos` for `github_oauth`.

### 3. Install and connect

Open **Settings → Connections**, start the GitHub App (`github`) connection, and follow the installation flow. Choose the personal account or organization, select all repositories or only the repositories your workflows need, complete the Setup URL flow, and save the connection. For an ordinary user connection, select GitHub OAuth (`github_oauth`) and complete its OAuth flow.

### 4. Save and enable a workflow

Select either connection type in a GitHub node or tools node. Select `github` for an event trigger. Configure the event subscription and typed or raw trigger filter, save the workflow, and enable it. For a failed-CI workflow, use the `workflow_run` subscription and filter for action `completed`, the desired branch, and conclusion `failure`.

## Permissions and capabilities

GitHub's exact permission levels are **Read-only** and **Read & write**. Start with **Read-only** and grant **Read & write** only where a workflow creates or comments on resources.

| GitHub permission | Canopy capability | Minimum level |
| --- | --- | --- |
| Metadata | Installation and repository identity | Read-only |
| Issues | List issues and receive `issues`; create issues and comments | Read-only; Read & write to create |
| Pull requests | List pull requests and receive `pull_request`; create pull requests | Read-only; Read & write to create |
| Actions | Receive `workflow_run` events | Read-only |
| Checks | Receive `check_run` and `check_suite` events | Read-only |
| Contents | Receive `push` events | Read-only |

Canopy doesn't need Contents write or Workflows write. API-only use needs Metadata Read-only, plus Issues and Pull requests Read-only for list/get. Add Issues Read & write for issue creation or comments, and Pull requests Read & write for pull request creation.

## Webhooks and event triggers

Subscribe the App to the events required by your workflow. Canopy provides typed trigger presets for `workflow_run`, `check_run`, `check_suite`, `pull_request`, `push`, and `issues`. These require the matching subscription and permission: Actions Read-only for `workflow_run`, Checks Read-only for check events, Pull requests Read-only for `pull_request`, Contents Read-only for `push`, and Issues Read-only for `issues`.

A failed-CI trigger commonly filters `workflow_run` to action `completed`, branch `main`, and conclusion `failure`. Raw event mode matches the exact `X-GitHub-Event` name and optional action. It doesn't bypass GitHub permissions: subscribe to that event and grant the permission GitHub requires.

## Permissions JSON for custom Apps

In **Settings → Custom Apps**, Permissions JSON records the App permissions declared for the workspace; it doesn't grant permissions in GitHub by itself:

```json
{
  "metadata": "read",
  "issues": "write",
  "pull_requests": "write",
  "actions": "read",
  "checks": "read",
  "contents": "read"
}
```

Workflows can now handle failed CI, issue and pull-request intake, push and check reactions, and list/get/create/comment/pull-request operations. Selected AI Agent GitHub tools are also available through the GitHub tools node; enable write tools deliberately and require confirmation for write actions.

## Minimum configurations

- API operations: Metadata Read-only; Issues and Pull requests Read-only for list/get, with Read & write only for create/comment operations. No webhook is needed.
- Failed CI: Metadata Read-only, Actions Read-only, and the `workflow_run` subscription.
- Event automation: Metadata Read-only plus only the event permissions and subscriptions used by the workflow.

## Troubleshooting

- **Missing organization or repository:** for an App, check the installation account, repository selection, organization approval, and selected installation. For OAuth, check the authorized user and `repo` or `public_repo` scope.
- **Webhook signature errors:** verify the App source, callback URL, and exact secret on both GitHub and Canopy. Replace it on both sides if regenerated.
- **No workflow starts:** check **Active**, event subscription, repository selection, exact `owner/name`, and event/action/branch/conclusion filters.
- **Permission errors:** update the App permission, save it in GitHub, and refresh or approve the installation. Read-only cannot create issues, comments, or pull requests.
- **Private-key errors:** use the downloaded PEM with line breaks intact; custom sources can save the field again in **Settings → Custom Apps**.
- **SAML or organization policy blocks access:** authorize the GitHub user or App and ask an organization owner to approve the installation.
