# OAuth sign-in not redirecting on the server

> signInWithOAuth in a server action or route does nothing, or the user comes back signed out. On the server you must redirect to data.url yourself and exchange the code in a callback route.

Source: https://supahost.app/kb/oauth-server-side-redirect · Updated 2026-11-11

## What you see

- A server action or API route calls `supabase.auth.signInWithOAuth()` and nothing happens. There's no error and no redirect to GitHub or Google.
- Or the provider screen appears, but the user returns to `/auth/callback?code=...` and is still signed out.
- Or the callback fails with `invalid request: both auth code and code verifier should be non-empty`.

## Why it happens

In the browser, `signInWithOAuth()` sends the window to the provider for you. On the server there's no window, so the method only returns the provider URL in `data.url`. Your code has to send the redirect.

Server-side sign-in also uses the PKCE flow. Auth comes back to your app with a `code`, and your callback must swap it for a session with `exchangeCodeForSession()`. That swap needs the code verifier the server client saved in a cookie when sign-in started. If the client can't write cookies, or nothing handles `/auth/callback`, the user never gets a session.

## How to fix it

These steps use the Next.js App Router with `@supabase/ssr`. The server client in `lib/supabase/server.ts` must implement both `getAll` and `setAll` for cookies; see [Auth in Next.js](/docs/auth/nextjs).

1. **Redirect to `data.url` in the server action:**

   ```ts
   // app/login/actions.ts
   "use server";

   import { headers } from "next/headers";
   import { redirect } from "next/navigation";
   import { createClient } from "@/lib/supabase/server";

   export async function signInWithGitHub() {
     const supabase = await createClient();
     const origin = (await headers()).get("origin");

     const { data, error } = await supabase.auth.signInWithOAuth({
       provider: "github",
       options: { redirectTo: `${origin}/auth/callback` },
     });

     if (error) redirect("/login?error=oauth");
     redirect(data.url);
   }
   ```

   Don't put `redirect()` inside a `try/catch`. Next.js implements it by throwing, and the catch swallows the redirect.

2. **Exchange the code in a callback route:**

   ```ts
   // app/auth/callback/route.ts
   import { NextResponse, type NextRequest } from "next/server";
   import { createClient } from "@/lib/supabase/server";

   export async function GET(request: NextRequest) {
     const { searchParams, origin } = new URL(request.url);
     const code = searchParams.get("code");

     if (code) {
       const supabase = await createClient();
       const { error } = await supabase.auth.exchangeCodeForSession(code);
       if (!error) return NextResponse.redirect(`${origin}/team`);
     }
     return NextResponse.redirect(`${origin}/login?error=callback`);
   }
   ```

3. **Allow the callback URL.** Add `http://localhost:3000/**` and your production address (for example `https://chat.example.com/**`) under Dashboard → your project → **Auth** tab → **Redirect URLs**, then click **Save Auth settings**. Without this, Auth ignores `redirectTo` and sends users to the Site URL.

4. **Start and finish in the same browser.** The code verifier cookie lives in the browser that started sign-in. Test in a normal tab, not one browser for the form and another for the callback.

## On SupaHost

- There are two different callback URLs. The provider (GitHub, Google and so on) redirects to your project's Auth: `https://app-one.acme.supahost.space/auth/v1/callback`, which you register in the provider's console. Auth then redirects to your app's `/auth/callback`, which goes in **Redirect URLs**.
- Once a custom domain is active on the project, the provider callback uses that domain instead. Update the provider's console when you add one.

## Related

- [Auth in Next.js (App Router)](/docs/auth/nextjs)
- [Social login (OAuth)](/docs/auth/social-login)
- [PKCE errors: code verifier, cannot parse response](/kb/pkce-flow-errors)
- [Redirected to the wrong URL after sign-in](/kb/redirect-to-wrong-url)
