---
id: w2/m8/t004
title: REST — connect · callback · get/delete connection · GET /v1/repos
worker: worker2
status: done
estimate: 45m
depends_on: [w2/m8/t003]
---

## Objective

The REST surface over the t003 verbs: start an install, receive GitHub's post-install redirect, inspect/remove the connection, and list the installation's repos.

## Context

- Endpoints: `POST /v1/git/connect` → `{installUrl}` (built from `BEX_GITHUB_APP_SLUG`); `GET /v1/git/callback?installation_id=…` (GitHub App "Setup URL" target — records the installation via `Connect`, then redirects to the dashboard settings page via `BEX_DASHBOARD_URL` when set); `GET /v1/git/connection` · `DELETE /v1/git/connection`; `GET /v1/repos` (paginated passthrough of the t002 listing).
- `GET /v1/repos` is a **bex extension** — Render has no public repo-list REST; shape it from the t002 repo item, don't invent Render fields.
- Mount pattern: follow `apikeys/rest.go` (routes registered in `internal/api`).
- The callback carries no bearer (browser redirect from GitHub) — decide and document its auth: require a logged-in dashboard session on the redirect target, with the recorded installation validated server-side by token mint (t003) so a forged `installation_id` bex can't authenticate against is rejected.

## Steps

1. `rest.go` in `internal/github` with the five routes; error shapes match the rest of bex-api (403/404/503 conventions).
2. Callback flow: validate + record + redirect; missing/invalid `installation_id` → 400.
3. Handler tests: happy paths, 503 unconfigured, forged installation rejected, repos pagination params.

## Files

- `lego/backend/internal/github/rest.go` (new) + tests
- `lego/backend/internal/api/` (route mounting)

## Acceptance criteria

- [ ] All five endpoints live behind the OAuth gate (callback's distinct auth documented in the ADR)
- [ ] `GET /v1/repos` returns the connected installation's repos incl. private ones
- [ ] Handler tests cover 503 / forged-installation / pagination

## Out of scope

- GraphQL/MCP (t005); dashboard card (t006)
