---
title: "GitHub"
description: "Use GitHub sign-in for MainSDK auth - OAuth app setup, callback URLs, main.yaml, client secrets, local testing and swapping to another provider."
section: "integrations"
canonical: "https://mainsdk.dev/docs/integrations/github"
updated: "2026-10-28"
---

# GitHub

> Use GitHub sign-in for MainSDK auth - OAuth app setup, callback URLs, main.yaml, client secrets, local testing and swapping to another provider.

Canonical: https://mainsdk.dev/docs/integrations/github · Updated: 2026-10-28

GitHub is the default driver behind [`auth`](https://mainsdk.dev/docs/interfaces/auth) in the catalog. People sign in to your app with their GitHub account, and `auth` turns that into a short-lived, device-bound session your routes can trust. Pick GitHub when your users are developers who already have an account, such as a developer tool, an internal dashboard or a CLI with a web console. For a consumer app, a provider that holds its own user directory, such as Clerk or Auth0, is usually a better fit.

> **Note:** The catalog lists GitHub as the default `auth` driver; the `auth` spec's example still uses Clerk. The spec is due to be updated, and both drivers are in the drivers list.

## Interfaces it serves

### Sign-in and sessions (`auth`)

- Status: Building for 0.3 · ships as a stable API
- Driver: `github` (GitHub, default). owner default; spec to be updated
- Docs: https://mainsdk.dev/docs/interfaces/auth.md

```yaml
auth:
  driver: github
```

Swap to another provider: `clerk`, `auth0`, `better-auth`, `workos`, `supabase`, `local`.

### Connections to other services (`connections`)

- Status: Building for 0.3 · ships as a experimental API
- Driver: `github` (GitHub)
- Docs: https://mainsdk.dev/docs/interfaces/connections.md

```yaml
connections:
  driver: github
```

Swap to another provider: `google`, `slack`, `microsoft`, `notion`, `atlassian`, `airtable`, `partner`, `local`.

### Connectors to GRC, privacy, vulnerability and ticket tools (`connectors`)

- Status: Building for 1.2 · ships as a beta API
- Driver: `github` (GitHub Issues)
- Docs: https://mainsdk.dev/docs/interfaces/connectors.md

```yaml
connectors:
  driver: github
```

Swap to another provider: `servicenow-irm`, `archer`, `onetrust-grc`, `transcend`, `onetrust-privacy`, `dependency-track`, `snyk`, `wiz`, `defectdojo`, `jira`, `local`.

## Before you start

You need a GitHub account, and you register your app with GitHub as an OAuth app, either under your personal account or under an organisation you administer.

1. **Register an OAuth app.** In your GitHub developer settings (or your organisation's settings), create a new OAuth app. Give it a name your users will recognise on the consent screen.
2. **Set the homepage URL** to your app's public address, for example `https://shop.pinecart.dev`.
3. **Set the authorization callback URL** to the route in your app that receives GitHub's redirect after sign-in. The path MainSDK mounts for the callback is not defined yet [TBD]. An OAuth app has one callback URL, so register a separate OAuth app for local development, stage and production.
4. **Copy the client ID and generate a client secret.** GitHub shows the client secret once; copy it straight into your secrets manager. You can generate a new secret later and delete the old one to rotate it.
5. **Decide what you read about the user.** Some people keep their GitHub email address private. If your app needs an email, request the scope that grants access to the user's email addresses, and handle users who have none verified.

Store the client ID and secret in your secrets manager, never in code or a committed env file.

## Configure

```yaml title="main.yaml"
auth:
  driver: github
  methods: [passkeys]
  # [TBD] key names for the OAuth app; suggested secrets: GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET
  session: { ttl: 15m, refresh: 7d, bind: dbsc }
```

The `auth` spec does not yet define the keys a driver uses for its credentials. When it does, they take `secret:` references; a literal secret in `main.yaml` fails `mainsdk check`. Point each environment's secrets at the OAuth app registered for that environment.

## Use it

Guard a route with `auth.require()`. Without a valid session it answers 401 with `MAIN-AUTH-0001` and a `fix`.

```ts title="app/api/me/route.ts"
import { auth } from "mainsdk";

export async function GET(req: Request) {
  const session = await auth.require(req);
  return Response.json(session.user);
}
```

Ask for a role, a phishing-resistant method and a recent sign-in on sensitive routes:

```ts title="app/api/admin/route.ts"
import { auth } from "mainsdk";

export async function DELETE(req: Request) {
  await auth.require(req, { role: "admin", aal: "aal2", fresh: "5m" });
  return new Response(null, { status: 204 });
}
```

Where signing in is optional, call `auth.session(req)`; it returns the session or `null`.

## Local development and testing

- **No OAuth app yet:** the `local` auth driver is for development only and needs no GitHub registration.
- **Real GitHub sign-in on your machine:** register a separate OAuth app whose callback URL points at `http://localhost` on your dev port, and use its client ID and secret in your local secrets.
- **Tests:** `createTestApp()` from `@mainsdk/testing` runs `auth` on its in-memory fake, so tests never call GitHub. `chaos.on("auth", { outage: true })` simulates GitHub being unreachable; `auth.require()` fails closed.

```ts title="app/api/me/route.test.ts"
import { it } from "node:test";
import assert from "node:assert/strict";
import { createTestApp } from "@mainsdk/testing";
import { GET } from "./route";

it("auth.AC1 refuses a request with no session", async () => {
  createTestApp({ main: "./main.yaml" });
  const res = await GET(new Request("http://localhost/api/me"));
  assert.equal(res.status, 401);
});
```

## What MainSDK adds on top

- Short-lived, HttpOnly, Secure, SameSite sessions with rotating refresh tokens, never stored in `localStorage`.
- Passkeys by default, phishing-resistant, with the browser's cross-device QR at no extra code.
- Fails closed when GitHub cannot be reached.
- WhatsApp codes and SSO for your customers' organisations, provided in your app where the driver lacks them; every recovery audited and never weaker than sign-in.

See [Sign-in and sessions](https://mainsdk.dev/docs/interfaces/auth) for the full contract.

## Limits and notes

- People sign in with their own GitHub accounts, so you don't hold a user directory at GitHub; profile and role data live in your own `db`.
- How the GitHub driver combines with passkeys, WhatsApp and SSO is declared in its capability profile; `mainsdk check` names any method it lacks.
- GitHub is a global service; residency in MainSDK's US, EU and India regions applies to the records you store about users, not to the GitHub account.
- `auth.raw()` returns the provider client for features `auth` does not wrap. `mainsdk check` lists every use.

## Swap to or from it

```yaml title="main.yaml"
auth:
  driver: clerk   # was github
```

> **Warning:** Identity is stateful. Sessions and any user records your provider holds move only through a migration that MainSDK runs as a guided job with a rollback. Going from GitHub to a provider with its own directory means mapping each GitHub identity to a user there; plan it before you switch.

## FAQ

**Do I need a GitHub OAuth app to start building?** No. Use the `local` driver in development and the fake in tests. Register an OAuth app when you want real GitHub sign-in.

**Why one OAuth app per environment?** Each OAuth app has a single callback URL, so local, stage and production each need their own registration and their own client secret.

**Can I use a GitHub App instead of an OAuth app?** This page covers OAuth apps only. Whether the driver supports GitHub Apps for sign-in is not specified.

## Next

- [Sign-in and sessions](https://mainsdk.dev/docs/interfaces/auth) and [Permissions](https://mainsdk.dev/docs/interfaces/access)
- [Clerk](https://mainsdk.dev/docs/integrations/clerk), [Auth0](https://mainsdk.dev/docs/integrations/auth0) and [WorkOS](https://mainsdk.dev/docs/integrations/workos)
- [Swap a driver](https://mainsdk.dev/docs/guides/swap-a-driver)
