Central authentication service with multiple tenant support using GitHub OAuth and GitHub App.
┌─────────────────────┐
│ Tenant A (:3001) │───┐
└─────────────────────┘ │ ┌─────────────────────┐ ┌─────────────┐
├────▶│ Auth Service (:3000)│────▶│ GitHub │
┌─────────────────────┐ │ └─────────────────────┘ └─────────────┘
│ Tenant B (:3002) │───┘
└─────────────────────┘
poc-app/
├── auth-service/
│ └── main.go
├── tenant-service/
│ └── main.go
└── README.md
Go to https://github.com/settings/apps and create a new GitHub App:
- App name: your-app-name
- Homepage URL: http://localhost:3000
- Callback URL: http://localhost:3000/callback
- Request user authorization during installation: ✓
- Webhook Active: uncheck
Permissions:
- Repository: Contents (Read & Write)
- Repository: Issues (Read & Write)
- Repository: Workflows (Read & Write)
- Account: Email addresses (Read-only)
After creation, generate a Client Secret and note the Client ID.
export GITHUB_CLIENT_ID="your_client_id"
export GITHUB_CLIENT_SECRET="your_client_secret"
export GITHUB_APP_SLUG="your-app-name"Open 3 terminal windows:
Terminal 1 - Auth Service:
cd auth-service
go run main.goTerminal 2 - Tenant A:
cd tenant-service
TENANT_NAME="Acme Corp" PORT=3001 go run main.goTerminal 3 - Tenant B:
cd tenant-service
TENANT_NAME="Globex Inc" PORT=3002 go run main.go-
Open http://localhost:3001 → Acme Corp login page
-
Click "Sign in with GitHub"
-
Authorize and install GitHub App (select repositories)
-
You will see the dashboard with your repos
-
Open http://localhost:3002 → Globex Inc login page
-
Click "Sign in with GitHub"
-
Same flow, ends up on Globex Inc dashboard
-
Logout and login again → Goes directly to dashboard (no installation prompt)
- User clicks "Sign in with GitHub" on Tenant
- Tenant redirects to Auth Service
/login?tenant=URL - Auth Service stores tenant URL in state, redirects to GitHub OAuth
- User authorizes on GitHub
- GitHub calls Auth Service
/callbackwith code - Auth Service exchanges code for token, gets user info
- Auth Service creates temp token, redirects to Tenant
/auth/complete - Tenant exchanges temp token with Auth Service
/exchange - User has no InstallationID → Redirect to GitHub App installation
- User selects repositories and installs
- GitHub calls Auth Service
/callbackwith installation_id - Auth Service redirects to Tenant with installation_id
- Tenant saves user with InstallationID, redirects to Dashboard
- User clicks "Sign in with GitHub" on Tenant
- Same OAuth flow (steps 2-8)
- Tenant checks: User exists in DB with InstallationID
- Preserve existing InstallationID
- Redirect directly to Dashboard (skip installation)
| Variable | Required | Default | Description |
|---|---|---|---|
| GITHUB_CLIENT_ID | Yes | - | GitHub App Client ID |
| GITHUB_CLIENT_SECRET | Yes | - | GitHub App Client Secret |
| GITHUB_APP_SLUG | Yes | - | GitHub App slug from URL |
| AUTH_SERVICE_URL | No | http://localhost:3000 | Auth service public URL |
| PORT | No | 3000 | Server port |
| Variable | Required | Default | Description |
|---|---|---|---|
| TENANT_NAME | No | Tenant | Display name for tenant |
| PORT | No | 3001 | Server port |
| TENANT_URL | No | http://localhost:{PORT} | Tenant public URL |
| AUTH_SERVICE_URL | No | http://localhost:3000 | Auth service URL |
| Endpoint | Description |
|---|---|
| GET /login?tenant=URL | Start OAuth flow, stores tenant URL in state |
| GET /callback | GitHub OAuth/Installation callback |
| GET /install?tenant=URL | Start GitHub App installation |
| GET /exchange?token=XXX | Exchange temp token for user data |
| Endpoint | Description |
|---|---|
| GET / | Login page |
| GET /auth/github | Redirects to Auth Service /login |
| GET /auth/complete?token=XXX | Receives callback from Auth Service |
| GET /install | Redirects to Auth Service /install |
| GET /dashboard | Shows user info and repositories |
| GET /logout | Clears session |