# Git Provider Setup This document covers manual setup for GitHub OAuth, Puter Git (Gitea), webhooks, and Convex environment variables. > **Never place admin or user tokens in checked-in `.env` files or browser variables.** All secrets must be Convex environment variables set via `npx convex env set`. ## GitHub OAuth Application 1. Go to GitHub **Settings → Developer settings → OAuth Apps** and open the app whose client ID will be stored in Convex. 2. Set the application name and homepage URL. The homepage URL should be the current `SITE_URL`. 3. Set the single **Authorization callback URL** to exactly: ```text /api/auth/callback/github ``` GitHub OAuth Apps support one callback URL. Scheme, host, port, and path must match the `redirect_uri` sent by Better Auth exactly. 4. Generate a client secret. 5. Set the credentials on the Convex deployment—not only in the local `.env` file: ```bash cd packages/backend npx convex env set GITHUB_CLIENT_ID npx convex env set GITHUB_CLIENT_SECRET npx convex env list ``` The configured `SITE_URL`, GitHub callback URL, and browser URL are one unit. For a shared Convex deployment, switch all three before testing a different public origin. See [Auth Proxy](./auth-proxy.md#one-origin-per-shared-oauth-deployment) for the deployment boundary. ### Requested scopes Zopu requests GitHub identity and private-repository access: `read:user`, `user:email`, `repo`, and `read:org`. `repo` grants access to private repositories; `read:org` permits organization repository discovery. ## GitHub Webhook (manual setup for OAuth-based version) 1. Go to the GitHub repository Settings > Webhooks > Add webhook. 2. Payload URL: `/api/git/webhooks/github` 3. Content type: `application/json` 4. Secret: generate a strong random string and set it as: ``` npx convex env set GITHUB_WEBHOOK_SECRET ``` 5. Select individual events: - Push - Repository (created, deleted, transferred, renamed, visibility) - Delete - Create - Public - Fork 6. Do not select "Send me everything." ## Puter Git (Gitea) Admin Token 1. As a Gitea admin, go to Settings > Applications > Generate New Token. 2. Select scopes: `write:admin`, `write:organization`, `write:repository`. 3. Set the token: ``` npx convex env set PUTER_GIT_ADMIN_TOKEN ``` This token is used only for platform administration (user creation, organization creation, repository creation, migration). It is never used for end-user operations. ## Puter Git Webhook After a repository is created or migrated, Zopu ensures a webhook is configured automatically. If manual setup is needed: 1. Go to the Gitea repository Settings > Webhooks > Add Webhook > Gitea. 2. Target URL: `/api/git/webhooks/puter` 3. HTTP method: POST 4. Content-Type: `application/json` 5. Secret: generate a strong random string and set it as: ``` npx convex env set GITEA_WEBHOOK_SECRET ``` 6. Trigger on: Push events, Repository events. ## Credential Encryption Key Generate a 32-byte encryption key for AES-GCM credential encryption: ```bash openssl rand -base64 32 | base64 | tr -d '\n' | pbcopy ``` Set it as: ``` npx convex env set GIT_CREDENTIAL_ENCRYPTION_KEY ``` The key must be exactly 32 bytes when base64url-decoded. ## Same-Origin Proxy for Better Auth Callbacks Better Auth requires the callback URL to be on the same origin as `SITE_URL`. If your Convex deployment uses a different origin: 1. Configure a reverse proxy (e.g., Caddy) to forward `/api/auth/*` to the Convex deployment. 2. Set `SITE_URL` to the proxy origin. 3. Set `CONVEX_SITE_URL` to the Convex deployment URL. ## Validation Procedures ### Verify a Puter PAT connection 1. Connect a Puter PAT through the UI. 2. Verify the connection state shows `active`. 3. List private repositories to confirm token validity. ### Verify GitHub OAuth 1. Click "Connect GitHub" in the UI. 2. Complete the GitHub OAuth flow. 3. Verify the connection state shows `active`. ### OAuth diagnostics | Symptom | Cause | Fix | | --- | --- | --- | | `Provider not found` from `/api/auth/link-social` | `GITHUB_CLIENT_ID` or `GITHUB_CLIENT_SECRET` is absent from the Convex deployment env store. A local `.env` does not configure cloud functions. | Set both variables with `npx convex env set` and verify with `npx convex env list`. | | GitHub `Invalid Redirect URI` | GitHub's saved callback does not exactly equal the app's `redirect_uri`. | Set the OAuth App's single callback to `/api/auth/callback/github`. | | `state_mismatch` at a `convex.site` page | Better Auth started on the public origin but GitHub returned to the direct Convex host, so the public-origin state cookie is unavailable. | Set Better Auth `baseURL` to `SITE_URL`; proxy `/api/auth/*` through the public origin. | | `email_doesn't_match` after selecting GitHub | A deployment predates the explicit-link policy or has not received the current auth configuration. | Deploy the current backend. Explicit `linkSocial` allows a different GitHub email without changing the Zopu account email. | | `externalEmail` is `null` during `connectGithub` | The GitHub account hides its public email; GitHub returns `null` from `/user`. | Deploy the current backend, which normalizes nullable provider emails before Convex persistence. | GitHub connections are explicit authenticated account links. The linked GitHub email may differ from the existing Zopu account email; Zopu retains the existing account email and only stores the GitHub identity and OAuth credential needed for repository access. ### Reconnection If a token is expired or revoked: 1. The connection state shows `reauth-required`. 2. Reconnect the provider through the UI. 3. The old connection state is updated to `active`. 4. Projects, repositories, Work, and artifacts are not deleted. ## Environment Variables Summary | Variable | Required | Description | | --- | --- | --- | | `SITE_URL` | Yes | Public-facing URL | | `CONVEX_SITE_URL` | Yes | Convex deployment URL (may differ from SITE_URL with proxy) | | `GIT_CREDENTIAL_ENCRYPTION_KEY` | Yes | Base64url-encoded 32-byte AES-GCM key | | `PUTER_GIT_ADMIN_TOKEN` | Yes | Gitea admin token for provisioning | | `GITHUB_CLIENT_ID` | For GitHub | OAuth app client ID | | `GITHUB_CLIENT_SECRET` | For GitHub | OAuth app client secret | | `GITHUB_WEBHOOK_SECRET` | For GitHub webhooks | HMAC verification secret | | `GITEA_WEBHOOK_SECRET` | For Puter webhooks | HMAC verification secret | | `FLUE_DB_TOKEN` | Yes | Private agent backend token | | `FLUE_URL` | Optional | Private agent backend URL | | `NATIVE_APP_URL` | Optional | Native app deep-link scheme |