From 5ad1450ca5edb86774b63bf9f40e27495551c27c Mon Sep 17 00:00:00 2001 From: Mayur-e Date: Wed, 27 May 2026 16:28:12 +0530 Subject: [PATCH 1/2] fix(auth): resolve GitHub OAuth error=github redirect loop - Add supabaseAdmin null guard in signIn callback: when Supabase env vars are missing or contain placeholder values, supabaseAdmin is null and calling .from() on it throws a TypeError that NextAuth silently converts to error=github. Now logs a warning and returns true so auth succeeds with degraded functionality instead of crashing. - Wrap Supabase upsert in try/catch: transient DB errors (table missing, network issues) no longer block authentication. Errors are logged to the server console for operator visibility. - Add AuthErrorBanner to sign-in page: reads the ?error= query param via useSearchParams() and maps NextAuth error codes to human-readable messages (github, OAuthCallback, OAuthSignin, Configuration, AccessDenied). Wrapped in Suspense boundary for Next.js 14 static generation compatibility. Clears the param from the URL after display so stale errors do not persist across page refreshes. - Fix landing page sign-in links: all CTA and nav links that previously used raw href to /api/auth/signin/github (bypassing NextAuth CSRF token validation and causing immediate error=github) now navigate to /auth/signin instead, preserving the intended UX flow. - Expand DEVELOPMENT.md troubleshooting with a dedicated error=github redirect loop checklist covering all known root causes. Fixes # --- DEVELOPMENT.md | 76 ++++++++++++++++++- src/app/auth/signin/page.tsx | 100 ++++++++++++++++++++++++- src/components/landing/LandingPage.tsx | 6 +- src/lib/auth.ts | 15 ++++ src/lib/supabase.ts | 1 - 5 files changed, 190 insertions(+), 8 deletions(-) diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index 702a3bab..73f47470 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -263,11 +263,83 @@ export async function GET() { ``` [next-auth][error][NO_SECRET] ``` -Add `NEXTAUTH_SECRET` to `.env.local`. +Add `NEXTAUTH_SECRET` to `.env.local`. Generate one with: +```bash +# macOS / Linux +openssl rand -base64 32 +# Windows PowerShell +[Convert]::ToBase64String((1..32 | ForEach-Object { Get-Random -Maximum 256 })) +``` + +--- + +### GitHub OAuth `error=github` Redirect Loop + +**Symptom:** After clicking "Sign in with GitHub" and completing the GitHub flow, the browser redirects back to `/auth/signin?error=github` instead of the dashboard. + +Work through this checklist in order: + +#### 1. Missing or placeholder env vars (most common cause) + +Open `.env.local` and confirm these four are set to real values (not `your_...` placeholders): + +```env +GITHUB_ID=Ov23... # from github.com/settings/developers +GITHUB_SECRET=ghp_... # generated in the same OAuth App +NEXTAUTH_SECRET=<32-byte> # run: openssl rand -base64 32 +NEXTAUTH_URL=http://localhost:3000 +``` + +Also required for the database upsert on sign-in: +```env +NEXT_PUBLIC_SUPABASE_URL=https://xxxx.supabase.co +SUPABASE_SERVICE_ROLE_KEY=eyJ... +``` + +If `NEXT_PUBLIC_SUPABASE_URL` or `SUPABASE_SERVICE_ROLE_KEY` are missing, the server log will print: +``` +signIn: supabaseAdmin is not configured; skipping DB upsert. +``` +Authentication will still succeed, but no user record will be written to Supabase. + +#### 2. Callback URL mismatch in the GitHub OAuth App + +The **Authorization callback URL** in your GitHub OAuth App must be **exactly**: + +``` +http://localhost:3000/api/auth/callback/github +``` + +Any trailing slash, different port, or HTTPS vs HTTP mismatch will cause `error=github`. Verify at [github.com/settings/developers](https://github.com/settings/developers) → your OAuth App → **Authorization callback URL**. + +#### 3. `ENCRYPTION_KEY` not set + +The `ENCRYPTION_KEY` is required for OAuth token encryption: + +```env +ENCRYPTION_KEY=<64 hex chars> # run: openssl rand -hex 32 +``` + +On Windows PowerShell: +```powershell +-join ((1..32) | ForEach-Object { "{0:x2}" -f (Get-Random -Maximum 256) }) +``` + +#### 4. Restart the dev server after changing env vars + +Next.js reads `.env.local` only at startup. After any change, stop and restart: + +```bash +npm run dev +``` + +#### 5. Check the server console for the real error + +The browser only shows `error=github` — the actual error is printed to the **terminal running `npm run dev`**. Look for lines starting with `[next-auth]` or `signIn:`. --- -### GitHub OAuth callback mismatch +### GitHub OAuth callback URL mismatch ``` The redirect_uri is not associated with this application ``` diff --git a/src/app/auth/signin/page.tsx b/src/app/auth/signin/page.tsx index b89babda..dad7bfc7 100644 --- a/src/app/auth/signin/page.tsx +++ b/src/app/auth/signin/page.tsx @@ -1,12 +1,80 @@ "use client"; import { signIn } from "next-auth/react"; -import { useEffect, useRef } from "react"; +import { Suspense, useEffect, useRef } from "react"; +import { useSearchParams } from "next/navigation"; + const A = "#818cf8"; +const ERR = "#f87171"; const MONO = "var(--font-jetbrains, ui-monospace, monospace)"; const DISP = "var(--font-syne, system-ui, sans-serif)"; +/** Maps NextAuth error codes → user-facing messages. */ +const AUTH_ERROR_MESSAGES: Record = { + github: + "GitHub sign-in failed. This is usually caused by incorrect OAuth credentials or a mismatched callback URL. Check your GitHub OAuth App settings and try again.", + OAuthCallback: + "The OAuth callback could not be completed. Please try signing in again.", + OAuthSignin: + "Could not start the GitHub sign-in flow. Please try again.", + Configuration: + "There is a server configuration error. Please contact the site administrator.", + AccessDenied: + "Access was denied. You may have cancelled the GitHub authorization.", + Verification: + "The sign-in link has expired or has already been used.", + Default: + "An unexpected authentication error occurred. Please try again.", +}; + +function getErrorMessage(error: string): string { + return AUTH_ERROR_MESSAGES[error] ?? AUTH_ERROR_MESSAGES.Default; +} + +function AuthErrorBanner({ error }: { error: string }) { + return ( +
+

+ ⚠ Sign-in failed +

+

+ {getErrorMessage(error)} +

+
+ ); +} + function MouseSpotlight() { const ref = useRef(null); useEffect(() => { @@ -35,7 +103,25 @@ function MouseSpotlight() { ); } -export default function SignInPage() { +/** + * Inner component that reads search params — must live inside a Suspense + * boundary because useSearchParams() opts the subtree out of static rendering. + */ +function SignInContent() { + const searchParams = useSearchParams(); + const error = searchParams.get("error"); + + // Clear the ?error= param from the URL immediately after reading it so + // that refreshing the page or navigating back doesn't show a stale error + // from a previous sign-in attempt. + useEffect(() => { + if (error && typeof window !== "undefined") { + const url = new URL(window.location.href); + url.searchParams.delete("error"); + window.history.replaceState({}, "", url.toString()); + } + }, [error]); + return (
+ {error && } +
); } + +export default function SignInPage() { + return ( + + + + ); +} diff --git a/src/components/landing/LandingPage.tsx b/src/components/landing/LandingPage.tsx index 2dba147e..e97d9921 100644 --- a/src/components/landing/LandingPage.tsx +++ b/src/components/landing/LandingPage.tsx @@ -156,7 +156,7 @@ function LandingNav() { DEVTRACK - + SIGN IN → @@ -402,7 +402,7 @@ function HeroSection() { {/* CTAs */}
- + @@ -667,7 +667,7 @@ function SetupSection() {
- + Sign in with GitHub ; function createUnavailableSupabaseAdmin(): SupabaseAdminClient { From 1ccb696656f0bc1dcea0c4c2d4f0940dd81c3a53 Mon Sep 17 00:00:00 2001 From: Mayur-e Date: Thu, 28 May 2026 18:14:12 +0530 Subject: [PATCH 2/2] fix(ci): fix YAML indentation error in e2e.yml at line 37 --- .github/workflows/e2e.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 62f222e0..68d65585 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -34,7 +34,7 @@ jobs: - name: Install app dependencies run: npm ci - - name: Install Playwright browsers + - name: Install Playwright browsers run: npx playwright install --with-deps chromium - name: Run Playwright tests