# GitHub social login via Kratos oidc — DONE 2026-07-11

Sign-in-with-GitHub for a developer PaaS: Kratos `oidc` method with a GitHub OAuth app (client id/secret via `auth-secrets.sh`), Ory Elements renders the provider button automatically. Blocked on: (1) who owns the GitHub OAuth app (per-installation for self-hosters — needs a docs answer, not just our app), (2) a credible local E2E story (Dex as a stand-in OIDC provider on the mock cluster?). Promote once both are answered.

## Resolution (implemented directly rather than promoted to a milestone)

Both blockers answered and the feature shipped in one pass — small enough that a full milestone wasn't warranted:

- **Blocker 1 (ownership):** each installation owns its own GitHub **OAuth app** (mirrors the self-hosted GitHub _App_ decision, `docs/ADR026-github-integration.md`); bex.co's hosted instance owns one. Callback URL `https://auth.<base-domain>/self-service/methods/oidc/callback/github`. Documented in `docs/ADR012-auth.md` §10.
- **Blocker 2 (local E2E):** `scripts/auth-oidc-e2e.sh` — a self-contained throwaway **Dex** stand-in OIDC provider + real Kratos (not the mock cluster; mirrors `auth-oauth21-e2e.sh`), driving login → provider → callback → first-party session. Green locally. `scripts/auth-oidc-verify.sh` is the read-only prod smoke (Secret/Deployment/rollout/login-flow); baseline-confirmed against Hetzner prod pre-ship (all pre-ship ✗ as expected), turns green after the deploy.

Implementation:

- `scripts/auth-secrets.sh` always writes an `oidc.yaml` key into the `kratos` Secret — the GitHub provider (id/secret from `.env`, `base64://` Jsonnet mapper) when `BEX_GITHUB_OIDC_*` are set, else `enabled: false`.
- `deploy/gitops/base/values/kratos.values.yaml` mounts it as a **second `--config`** file (Kratos deep-merges repeated `--config`), so the secret never lands in git; the local overlay inherits it.
- `.env.example`/`.env.template` + `gh-secrets.sh` + `deploy.yml` carry the two optional `BEX_GITHUB_OIDC_*` keys. No dashboard change — Ory Elements renders the provider button from the flow's `oidc` node.

Env-var naming: `BEX_GITHUB_OIDC_CLIENT_ID` / `BEX_GITHUB_OIDC_CLIENT_SECRET` — the `BEX_` prefix is load-bearing, **not** cosmetic: GitHub Actions rejects any secret name starting with the reserved `GITHUB_` prefix, so a bare `GITHUB_OIDC_*` would break `gh-secrets.sh` + `deploy.yml`'s `secrets.*` lookup and silently leave prod off.

Enabling social login is now `.env` + a re-deploy, with no git change.
