[PR #307] [MERGED] fix(sso): repair SSO login bounce + migrate to @better-auth/oauth-provider #6598

Closed
opened 2026-07-13 13:13:20 -05:00 by GiteaMirror · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/RayLabsHQ/gitea-mirror/pull/307
Author: @arunavo4
Created: 5/29/2026
Status: Merged
Merged: 6/2/2026
Merged by: @arunavo4

Base: mainHead: fix/sso-login-and-oauth-provider-migration


📝 Commits (6)

  • 06f9c13 fix(sso): repair SSO login bounce + migrate to @better-auth/oauth-provider
  • 0e6df2e fix(sso): finish SSO bounce repair — verified end-to-end against Authentik
  • df62e45 fix(sso): drop dynamic trustedProviders — rely on IdP's email_verified claim
  • 1e2ce9a fix(sso): domain-scoped account linking + rebuild snapshot chain
  • bc06f10 fix(sso): enable domainVerification so the model surfaces domainVerified
  • ceaf89b ci(e2e): retry docker compose pull on transient Docker Hub timeouts

📊 Changes

22 files changed (+5467 additions, -188 deletions)

View changed files

📝 .env.example (+3 -0)
📝 .github/workflows/e2e-tests.yml (+18 -0)
📝 .gitignore (+1 -0)
📝 bun.lock (+3 -0)
📝 docs/ENVIRONMENT_VARIABLES.md (+1 -0)
📝 docs/SSO-OIDC-SETUP.md (+20 -3)
📝 docs/SSO_TESTING.md (+50 -2)
drizzle/0012_oauth_provider_migration.sql (+126 -0)
drizzle/0013_slim_galactus.sql (+35 -0)
drizzle/meta/0012_snapshot.json (+2358 -0)
drizzle/meta/0013_snapshot.json (+2375 -0)
📝 drizzle/meta/_journal.json (+15 -1)
📝 package.json (+1 -0)
📝 scripts/validate-migrations.ts (+110 -0)
📝 src/components/oauth/ConsentPage.tsx (+15 -27)
📝 src/lib/auth-client.ts (+2 -2)
📝 src/lib/auth.ts (+97 -11)
📝 src/lib/db/index.ts (+4 -2)
📝 src/lib/db/schema.ts (+106 -45)
📝 src/pages/api/auth/oauth2/register.ts (+5 -5)

...and 2 more files

📄 Description

Fixes #306 and migrates the deprecated oidc-provider plugin to @better-auth/oauth-provider (the deprecation warning seen in the issue logs).

Warning

This bundles a low-risk bug fix with a breaking, IdP-side schema migration that could not be end-to-end tested locally. See "Verification status" below. Review the two halves independently.


Part 1 — #306 SSO login bounce (the reported bug)

The reporter clicks SSO (Authentik), is bounced back to /login. Root cause: after the OAuth round-trip the browser lands on / with no session, so MainLayout redirects to /login. The 401 /api/sso/applications in the report is unrelated noise (it backs the OAuth provider consent UI).

Fixes:

  • Account linking (src/lib/auth.ts): added account.accountLinking with trustedProviders: ["email-password"]. Better Auth enables linking by default, but auto-linking an SSO sign-in to a pre-existing email/password account only happens for trusted providers or verified emails — otherwise the sign-in fails and bounces. This is the most likely cause of #306.
  • Working debug logs: Better Auth does not read DEBUG (it's not the debug npm package), so the docs' DEBUG=better-auth:* was a no-op and the reporter saw nothing. Added a logger block driven by BETTER_AUTH_LOG_LEVEL (debug|info|warn|error, default warn). Updated docs/SSO_TESTING.md, docs/ENVIRONMENT_VARIABLES.md, .env.example.

This half is config/docs only and directly addresses #306.

Part 2 — oidcProvideroauthProvider migration (breaking, provider/IdP side)

  • auth.ts: oidcProvideroauthProvider; added required jwt() plugin (JWKS signing keys); ported getAdditionalUserInfoClaimcustomUserInfoClaims/customIdTokenClaims.
  • auth-client.ts: oidcClientoauthProviderClient.
  • ConsentPage.tsx: updated to the new /oauth2/consent flow (passes oauth_query, navigates to returned redirect_uri).
  • Schema (schema.ts): oauth_applicationsoauth_clients, reshaped oauth_access_tokens, new oauth_refresh_tokens, oauth_consentoauth_consents, plus jwks.
  • Migration 0012: data-preserving — copies registered clients and converts comma-separated redirect_urls → JSON string[]. Access tokens/consents are dropped (ephemeral / cheaply re-granted).
  • Rewrote /api/sso/applications and /api/auth/oauth2/register against the new plugin API (createOAuthClient / registerOAuthClient / *OAuthClient).
  • Added a 0012 upgrade fixture to scripts/validate-migrations.ts.

Verification status

Verified locally

  • Migration 0012 applies cleanly on a fresh DB; old tables dropped, new tables present; redirect_urls → JSON transform correct (asserted in the migration-validation fixture).
  • auth.ts constructs and exposes createOAuthClient / registerOAuthClient / oauth2Consent.
  • Full test suite: 289 pass / 0 fail.

⚠️ NOT verifiable locally — needs manual testing before merge (no IdP runtime; project can't run astro check/build locally)

  • End-to-end OAuth-provider flow: authorize → consent page → code → token → userinfo against a real relying party.
  • Migrated client secrets won't validate: legacy secrets were stored in plaintext; the new provider stores them hashed. Affected apps must rotate their secret after upgrade (called out in the migration file).
  • OIDC discovery: startup logs a warning that /.well-known/oauth-authorization-server sits under /api/auth (due to basePath). RPs expecting it at root may need the exported oauthProviderAuthServerMetadata handler mounted at /. Follow-up.

Test plan

  • Authentik SSO login links to the existing admin account (no bounce)
  • BETTER_AUTH_LOG_LEVEL=debug surfaces [Better Auth] callback trace
  • Register an OAuth client and complete an authorize→consent→token flow
  • Existing registered clients survive the upgrade (rotate secret)

🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/RayLabsHQ/gitea-mirror/pull/307 **Author:** [@arunavo4](https://github.com/arunavo4) **Created:** 5/29/2026 **Status:** ✅ Merged **Merged:** 6/2/2026 **Merged by:** [@arunavo4](https://github.com/arunavo4) **Base:** `main` ← **Head:** `fix/sso-login-and-oauth-provider-migration` --- ### 📝 Commits (6) - [`06f9c13`](https://github.com/RayLabsHQ/gitea-mirror/commit/06f9c1334293686f980201de6348063b52da90fb) fix(sso): repair SSO login bounce + migrate to @better-auth/oauth-provider - [`0e6df2e`](https://github.com/RayLabsHQ/gitea-mirror/commit/0e6df2e3ac3054f462c685f30c57042a4d25d17f) fix(sso): finish SSO bounce repair — verified end-to-end against Authentik - [`df62e45`](https://github.com/RayLabsHQ/gitea-mirror/commit/df62e4593eb85a20dea4852045fa5239da8aea38) fix(sso): drop dynamic trustedProviders — rely on IdP's email_verified claim - [`1e2ce9a`](https://github.com/RayLabsHQ/gitea-mirror/commit/1e2ce9a26b9254bdec978eb79598b2de755cbfc0) fix(sso): domain-scoped account linking + rebuild snapshot chain - [`bc06f10`](https://github.com/RayLabsHQ/gitea-mirror/commit/bc06f10cc8d91add44ecc9cc8ecc691f91c2351f) fix(sso): enable domainVerification so the model surfaces domainVerified - [`ceaf89b`](https://github.com/RayLabsHQ/gitea-mirror/commit/ceaf89bc2534c43ea36b067be3c314e4c1f0ada4) ci(e2e): retry docker compose pull on transient Docker Hub timeouts ### 📊 Changes **22 files changed** (+5467 additions, -188 deletions) <details> <summary>View changed files</summary> 📝 `.env.example` (+3 -0) 📝 `.github/workflows/e2e-tests.yml` (+18 -0) 📝 `.gitignore` (+1 -0) 📝 `bun.lock` (+3 -0) 📝 `docs/ENVIRONMENT_VARIABLES.md` (+1 -0) 📝 `docs/SSO-OIDC-SETUP.md` (+20 -3) 📝 `docs/SSO_TESTING.md` (+50 -2) ➕ `drizzle/0012_oauth_provider_migration.sql` (+126 -0) ➕ `drizzle/0013_slim_galactus.sql` (+35 -0) ➕ `drizzle/meta/0012_snapshot.json` (+2358 -0) ➕ `drizzle/meta/0013_snapshot.json` (+2375 -0) 📝 `drizzle/meta/_journal.json` (+15 -1) 📝 `package.json` (+1 -0) 📝 `scripts/validate-migrations.ts` (+110 -0) 📝 `src/components/oauth/ConsentPage.tsx` (+15 -27) 📝 `src/lib/auth-client.ts` (+2 -2) 📝 `src/lib/auth.ts` (+97 -11) 📝 `src/lib/db/index.ts` (+4 -2) 📝 `src/lib/db/schema.ts` (+106 -45) 📝 `src/pages/api/auth/oauth2/register.ts` (+5 -5) _...and 2 more files_ </details> ### 📄 Description Fixes #306 and migrates the deprecated `oidc-provider` plugin to `@better-auth/oauth-provider` (the deprecation warning seen in the issue logs). > [!WARNING] > **This bundles a low-risk bug fix with a breaking, IdP-side schema migration that could not be end-to-end tested locally.** See "Verification status" below. Review the two halves independently. --- ## Part 1 — #306 SSO login bounce (the reported bug) The reporter clicks SSO (Authentik), is bounced back to `/login`. Root cause: after the OAuth round-trip the browser lands on `/` with **no session**, so `MainLayout` redirects to `/login`. The `401 /api/sso/applications` in the report is unrelated noise (it backs the OAuth *provider* consent UI). **Fixes:** - **Account linking** (`src/lib/auth.ts`): added `account.accountLinking` with `trustedProviders: ["email-password"]`. Better Auth enables linking by default, but auto-linking an SSO sign-in to a *pre-existing email/password account* only happens for trusted providers or verified emails — otherwise the sign-in fails and bounces. This is the most likely cause of #306. - **Working debug logs**: Better Auth does **not** read `DEBUG` (it's not the `debug` npm package), so the docs' `DEBUG=better-auth:*` was a no-op and the reporter saw nothing. Added a `logger` block driven by **`BETTER_AUTH_LOG_LEVEL`** (`debug|info|warn|error`, default `warn`). Updated `docs/SSO_TESTING.md`, `docs/ENVIRONMENT_VARIABLES.md`, `.env.example`. This half is config/docs only and directly addresses #306. ## Part 2 — `oidcProvider` → `oauthProvider` migration (breaking, provider/IdP side) - `auth.ts`: `oidcProvider` → `oauthProvider`; added required `jwt()` plugin (JWKS signing keys); ported `getAdditionalUserInfoClaim` → `customUserInfoClaims`/`customIdTokenClaims`. - `auth-client.ts`: `oidcClient` → `oauthProviderClient`. - `ConsentPage.tsx`: updated to the new `/oauth2/consent` flow (passes `oauth_query`, navigates to returned `redirect_uri`). - **Schema** (`schema.ts`): `oauth_applications` → `oauth_clients`, reshaped `oauth_access_tokens`, new `oauth_refresh_tokens`, `oauth_consent` → `oauth_consents`, plus `jwks`. - **Migration `0012`**: data-preserving — copies registered clients and converts comma-separated `redirect_urls` → JSON `string[]`. Access tokens/consents are dropped (ephemeral / cheaply re-granted). - Rewrote `/api/sso/applications` and `/api/auth/oauth2/register` against the new plugin API (`createOAuthClient` / `registerOAuthClient` / `*OAuthClient`). - Added a `0012` upgrade fixture to `scripts/validate-migrations.ts`. ## Verification status ✅ **Verified locally** - Migration `0012` applies cleanly on a fresh DB; old tables dropped, new tables present; `redirect_urls` → JSON transform correct (asserted in the migration-validation fixture). - `auth.ts` constructs and exposes `createOAuthClient` / `registerOAuthClient` / `oauth2Consent`. - Full test suite: **289 pass / 0 fail**. ⚠️ **NOT verifiable locally — needs manual testing before merge** (no IdP runtime; project can't run `astro check`/build locally) - End-to-end OAuth-provider flow: authorize → consent page → code → token → userinfo against a real relying party. - **Migrated client secrets won't validate**: legacy secrets were stored in plaintext; the new provider stores them hashed. Affected apps must **rotate their secret** after upgrade (called out in the migration file). - OIDC discovery: startup logs a warning that `/.well-known/oauth-authorization-server` sits under `/api/auth` (due to `basePath`). RPs expecting it at root may need the exported `oauthProviderAuthServerMetadata` handler mounted at `/`. **Follow-up.** ## Test plan - [ ] Authentik SSO login links to the existing admin account (no bounce) - [ ] `BETTER_AUTH_LOG_LEVEL=debug` surfaces `[Better Auth]` callback trace - [ ] Register an OAuth client and complete an authorize→consent→token flow - [ ] Existing registered clients survive the upgrade (rotate secret) --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
GiteaMirror added the pull-request label 2026-07-13 13:13:20 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/gitea-mirror#6598