Skip to content

Integrations

All optional. Repro works fine without any of them.

GitHub Issues sync

A GitHub App (not OAuth) that lets the dashboard:

  • Create an issue from a report with one click, or automatically on intake
  • Mirror status two ways: close a Repro ticket → close the issue; close the issue → resolve the ticket

Repro generates the entire GitHub App for you — no manual form-filling. Each self-hosted instance creates its own app tied to its own domain, so your credentials never pass through any third-party server.

Prerequisites

  • ENCRYPTION_KEY is set in your .env (generate with openssl rand -base64 32). Required because the app's private key, webhook secret, and client secret are stored encrypted at rest in the github_app table.
  • You're signed in to the dashboard as an admin (not a project-scoped role).

Steps

  1. Open Settings → GitHub in the dashboard sidebar.
  2. Optionally type a GitHub organization slug (e.g. acme). Leave empty to create the app on your personal GitHub account.
  3. Click Create GitHub App. You'll be redirected to GitHub.
  4. Review the app details on GitHub's page and click Create GitHub App for…. GitHub creates the app and redirects back to Repro with a one-time code.
  5. Repro exchanges the code, stores the credentials encrypted, and redirects you to the GitHub settings page with a success banner.

That's it — no env vars to set.

Enable webhooks (one manual step)

GitHub refuses to create an app whose webhook URL isn't publicly reachable, so Repro creates the app with webhooks disabled. Two-way sync (GitHub issue closed → Repro ticket closed) needs webhooks enabled. Enable them after the app is created:

  1. On the success page, click your GitHub App settings page (or open https://github.com/settings/apps/<slug> directly).
  2. Scroll to the Webhook section.
  3. Set the Webhook URL to <BETTER_AUTH_URL>/api/integrations/github/webhook (for example, https://feedback.example.com/api/integrations/github/webhook).
  4. Check Active and click Save changes.

The webhook secret was generated and stored during setup — leave that field alone.

Local dev note. If BETTER_AUTH_URL is http://localhost:3000, the manifest wizard fills example.com as a placeholder webhook URL so GitHub's reachability check passes. Once you deploy to a real domain, update both the URL and the Active checkbox on GitHub.

Creating the GitHub App (legacy: env vars)

Skip this section if you used the manifest wizard above.

For deployments that prefer static configuration (Infrastructure-as-Code, secrets managers, etc.), you can create the app manually and wire it via env vars. The credential resolver prefers env vars over the in-app setup when both are present.

  1. Open github.com/settings/apps (or your org's App settings)
  2. Click New GitHub App
  3. Fill in:
    • GitHub App name: Repro (or whatever — the slug becomes public)
    • Homepage URL: your BETTER_AUTH_URL (e.g. https://feedback.example.com)
    • Callback URL: <BETTER_AUTH_URL>/api/integrations/github/install-callback
    • Setup URL: <BETTER_AUTH_URL>/api/integrations/github/install-callback (and tick Redirect on update)
    • Webhook URL: <BETTER_AUTH_URL>/api/integrations/github/webhook
    • Webhook secret: run openssl rand -hex 32, paste here AND save it for .env
  4. Repository permissions:
    • Issues: Read + write
    • Metadata: Read-only (required — GitHub auto-checks)
  5. Subscribe to events: Issues only. Installation and Installation repositories are auto-delivered — if you check them, GitHub rejects the form with "Default events unsupported".
  6. Where can this GitHub App be installed: your choice — Only on this account keeps it private
  7. Click Create GitHub App
  8. On the new App's settings page, scroll to Private keysGenerate a private key → a .pem file downloads
  9. Note the App ID at the top of the settings page

Wire it up:

ini
GITHUB_APP_ID=12345
GITHUB_APP_PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----\n...\n-----END RSA PRIVATE KEY-----"
GITHUB_APP_WEBHOOK_SECRET=<same secret you pasted into step 5>
GITHUB_APP_SLUG=<slug from https://github.com/apps/<slug>>

The GITHUB_APP_PRIVATE_KEY accepts either:

  • Literal PEM contents with newlines as \n (paste the whole file, replacing real newlines with \n)
  • An absolute path to a .pem file — the dashboard will readFile it at startup

For container deploys, mount the .pem as a Docker secret or bind-mount it read-only:

yaml
# compose.yaml override
services:
  dashboard:
    volumes:
      - ./github-app.pem:/secrets/github-app.pem:ro

Then GITHUB_APP_PRIVATE_KEY=/secrets/github-app.pem.

Installing the App on a repo

Once the app is set up (either path), open the dashboard → Project settings → GitHub. Click Install. GitHub walks you through picking the repo to install on. The dashboard receives the installation via webhook and saves it to the project's config.

Troubleshooting

Issues appear in Repro but never in GitHub — check docker compose logs dashboard | grep -i "github". Usually an invalid private key (key was not generated for this App) or a wrong GITHUB_APP_ID.

Webhook signature mismatch — the GITHUB_APP_WEBHOOK_SECRET in .env must match exactly what you pasted into GitHub's Webhook secret field.

Attachments don't render in issue bodies — the dashboard generates time-limited signed URLs that GitHub's image renderer fetches. If your BETTER_AUTH_URL is http://localhost:3000, GitHub's servers can't reach it. Use a real hostname + proxy.

OAuth sign-in

GitHub and Google OAuth via better-auth. Leave the secrets blank to hide the buttons.

GitHub OAuth App

  1. github.com/settings/developersOAuth AppsNew OAuth App
  2. Application name: Repro (or whatever)
  3. Homepage URL: your BETTER_AUTH_URL
  4. Authorization callback URL: <BETTER_AUTH_URL>/api/auth/callback/github
  5. Create, grab the Client ID and generate a Client secret
ini
GITHUB_CLIENT_ID=...
GITHUB_CLIENT_SECRET=...

Restart the stack — the "Sign in with GitHub" button shows up.

Google OAuth

  1. console.cloud.google.com → APIs & Services → Credentials
  2. Create Credentials → OAuth 2.0 Client ID → Web application
  3. Authorized redirect URIs: <BETTER_AUTH_URL>/api/auth/callback/google
  4. Copy the Client ID + Client secret
ini
GOOGLE_CLIENT_ID=...
GOOGLE_CLIENT_SECRET=...

Note: Google also requires a published OAuth consent screen before external users can sign in. In dev mode, only emails you add as test users can sign in.

Email (SMTP)

Any SMTP provider — SES, Postmark, Resend, SendGrid, Gmail, self-run Postfix.

ini
MAIL_PROVIDER=smtp
SMTP_HOST=smtp.resend.com
SMTP_PORT=587
SMTP_USER=resend
SMTP_PASS=re_xxxxxxxxxxxxxxxxxxx
SMTP_FROM="Repro <noreply@example.com>"

Verify a test magic-link email arrives: sign out → sign in → enter your email → check the inbox.

Common pitfalls

  • DMARC / SPF on your domain — if you're sending From: noreply@example.com, your sending domain needs SPF + DKIM set up or the mail lands in spam. Most providers have a setup checklist.
  • Port 465 vs 587 — 587 with STARTTLS is the modern default. 465 (implicit TLS) also works for most nodemailer setups.
  • Gmail SMTP — you'll need an App Password, not your account password. And their rate limits are strict enough that a small team might hit them on bulk invites.

Storage integrations

See Storage for S3-compatible endpoints (AWS, R2, B2, Hetzner, MinIO, Garage).

Released under the MIT License.