Desde

Self-hosting

The GitHub App

What the Viewer's GitHub App does, where its credentials live, and how to recover a deployment that can no longer connect to it.

The Viewer reaches GitHub through one GitHub App. It is how people sign in, how repositories are listed when you connect one to a project, how the build runner clones, and how a push triggers a rebuild. No personal tokens are stored anywhere: the App is the only credential the deployment holds.

This page covers creating that App, where its credentials live, and what to do when the Viewer reports it cannot connect to it.

Creating the App#

An Admin creates the App with one click: from Settings → GitHub, or from the Set up GitHub access step when connecting a repository for the first time. Choose whether the App belongs to your personal GitHub account or an organization, then press Create GitHub App. That takes you to github.com to confirm. GitHub creates the whole App and sends you back to the Viewer already configured. There is nothing to copy into .env.local, and no restart.

Under the hood, this is GitHub's App Manifest flow. The Viewer hands your browser a pre-filled manifest asking for read-only access to repository contents and email addresses, nothing else. Your browser posts that manifest to github.com as a normal form submit. GitHub creates the App and redirects back to the Viewer with a one-time code, which the Viewer exchanges for the App's credentials (private key, App ID, slug, client ID, client secret) and saves automatically. See where the App's credentials live below for what "saves" means.

If you can't use the one-click flow#

Register the App by hand instead when:

  • You're on GitHub Enterprise Server, or a locked-down organization. Some org policies block one-click App creation this way.
  • The deployment already has GitHub sign-in configured, and your only credential is the operator bearer token (VIEWER_ADMIN_TOKEN), not a signed-in Admin session. The bearer can start the flow, but GitHub's redirect back to the Viewer is a plain browser navigation, and a bearer token has no way to ride along on one. Sign in as an Admin in the browser first and the one-click flow works normally; only fall back to registering by hand if that isn't an option.

Go to github.com/settings/apps and choose New GitHub App:

  • Homepage URL: the origin the Viewer is reachable at, for example https://proto.internal.example.com.
  • Callback URL: that same origin plus /api/v1/auth/github/callback.
  • Account permissions → Email addresses: Read-only. Required. Sign-in falls back to reading the user's email list when their GitHub profile has no public email; without this permission, those people cannot sign in at all.
  • Repository permissions → Contents: Read-only. Enough to list and clone. Metadata read access is granted implicitly.
  • Webhook: leave it inactive unless you want push-triggered rebuilds right away. It only affects auto-deploy on push; nothing else needs it. (The one-click flow turns this on automatically, unless the Viewer's public URL is a loopback address.)

Then, on the App's settings page:

  1. Generate a private key and download the .pem.
  2. Note the App ID (a number).
  3. Note the App slug: the last segment of github.com/apps/<slug>.
  4. Note the App's own Client ID and Client secret. These are what sign-in uses.

Finally, install the App on the account or organization whose repositories you want to build, and set the values above as environment variables (VIEWER_GITHUB_APP_ID, VIEWER_GITHUB_APP_PRIVATE_KEY, VIEWER_GITHUB_APP_SLUG, VIEWER_GITHUB_CLIENT_ID, VIEWER_GITHUB_CLIENT_SECRET). See the Viewer configuration reference for the exact format each one expects.

Where the App's credentials live#

There are two possible sources, and the environment always wins:

  1. Environment variables: VIEWER_GITHUB_APP_ID, VIEWER_GITHUB_APP_PRIVATE_KEY, VIEWER_GITHUB_APP_SLUG, plus the sign-in pair. Setting any one of the three requires all three; the full table is in the Viewer configuration reference.
  2. config.json in the data directory: written automatically when an Admin creates the App from inside the product (Settings → GitHub). If you never set the env vars, this file is the App. It lives next to the database, inside VIEWER_DATA_DIR.

That second source is the one that gets lost. The database and config.json sit in the same directory but travel separately in people's heads: a database restored onto a fresh instance, or a redeploy that dropped the env vars, produces a Viewer that remembers every project and every repo connection, but has no way to reach GitHub.

Warning Back up the whole data directory, not just the database. config.json holds the App's private key and client secret; without it, the connections in the database point at an App the deployment can no longer speak for. The backup procedure covers this: it backs up the directory, not the file.

The Viewer can't connect to its GitHub App#

This is the state behind the banner in a project's repo settings ("This deployment can't connect to its GitHub App"), and behind Settings → GitHub showing the setup form on an instance that used to build fine. It means the process found no usable App credentials at boot: neither env vars nor a config.json record.

What still works: everything already published. Built prototypes keep serving, comments and reviewing work, invite and email sign-in work if configured. What doesn't: GitHub sign-in, listing repositories, builds, editing a repo connection, and push-triggered rebuilds.

First, work out which source the deployment was using:

  1. Did the process previously get VIEWER_GITHUB_APP_* env vars? Check the compose file, systemd unit, or secret store against what the running process actually receives. A redeploy that dropped them is the most common cause.
  2. If not, look for config.json in VIEWER_DATA_DIR. If the database was moved to this machine but config.json was not, this is your cause.

Then pick the remedy that matches. The two look similar and are not: one is a restore, the other is a reset.

If the App still exists on GitHub: restore its credentials#

Check https://github.com/settings/apps (or your organization's Settings → Developer settings → GitHub Apps). If the App is listed there, do not create a new one.

Restore the credentials from a backup of the data directory, or re-set the env vars. If the private key or client secret is lost, you don't need the old copy: the App's settings page on GitHub can generate a new private key and regenerate the client secret at any time (same App, new credentials). Set them, restart the process, and everything returns at once: sign-in, every installation, every connected repository, auto-deploy. Nobody reinstalls or reconnects anything.

If the App is gone, or this is a deliberately separate instance: create a new one#

An Admin creates a replacement the same way as first setup: the one-click flow from Settings → GitHub, or by hand if that flow isn't available. This is the right path when the App was deleted on GitHub, or when you cloned a deployment and the copy should not share the original's App (an App's callback URLs point at one host).

Know what it costs before you choose it:

  • Every repo connection must be redone. A stored connection builds through the installation id it was created with, and installation ids belong to one specific App. A new App gets new ids, so each project's repo settings must be opened and reconnected, even to the exact same repository.
  • The App must be installed again on every account and organization whose repositories people connect.
  • Everyone signs in again. The new App has a new OAuth client; existing accounts survive, but active GitHub sessions don't.

If you're unsure which case you're in, assume the App still exists and go look: restoring is strictly cheaper than replacing.