setup-guides

Google OAuth — Setup Guide

"Continue with Google" buttons live on /auth/signin and /auth/signup, and a "Link Google" affordance on /dashboard/settings. The flow uses Supabase's PKCE OAuth handshake — no env vars on the application side, all credentials live in the Supabase dashboard. This guide walks the one-time setup.

For the architectural detail (PKCE code-verifier cookie handling, server route handler, collision recovery, brand-aware redirects), see the Authentication section of ../ai/INDEX.md.


1. Create a Google OAuth client

You need a single OAuth 2.0 Client in Google Cloud Console that Supabase will use to authenticate users.

  1. Go to https://console.cloud.google.com/apis/credentials
  2. Create or select a project (a single project for HiveJournal is fine — the OAuth client is the unit of identity, not the project).
  3. Click + CREATE CREDENTIALS → OAuth client ID.
  4. If prompted, configure the OAuth consent screen first:
    • User type: External
    • App name: HiveJournal
    • User support email + Developer contact: your email
    • Authorized domains: hivejournal.com, graphene.fm, write.cafe, lovio.io, dreampro.io
    • Scopes: leave default (email + profile + openid). No sensitive scopes needed.
  5. Back on Create OAuth client ID:
    • Application type: Web application
    • Name: HiveJournal Supabase Auth (or similar)
    • Authorized redirect URIs: add exactly one — Supabase's callback URL:
      https://<your-supabase-project-ref>.supabase.co/auth/v1/callback
      
      You'll find this string in the Supabase dashboard under Authentication → Providers → Google (the "Callback URL (for OAuth)" field). Copy it verbatim.
    • Click CREATE.
  6. Copy the Client ID and Client secret from the modal that appears.

Common mistake: adding the brand-domain /auth/callback paths to the Google redirect URI list. Those go in Supabase, not Google. Google only ever talks to Supabase; Supabase then redirects to the brand domain.


2. Wire the provider in Supabase

  1. Open the Supabase dashboard → your project → Authentication → Providers → Google.
  2. Toggle Enable Sign in with Google ON.
  3. Paste the Google Client ID into the Client IDs field.
  4. Paste the Client secret into Client Secret (for OAuth).
  5. Leave Skip nonce checks and Allow users without an email OFF — the defaults are correct.
  6. Click Save at the bottom of the panel.

3. Allow the brand-domain callback URLs

Our app passes redirectTo: https://<brand-domain>/auth/callback to signInWithOAuth. Supabase rejects any redirectTo value that isn't on its Redirect URLs allowlist (security floor — prevents OAuth-based open-redirect attacks). Without this step, the user clicks Google on write.cafe and lands silently on hivejournal.com (Supabase's Site URL fallback).

  1. Open Authentication → URL Configuration.

  2. Under Redirect URLs, add a wildcard per host (one per line):

    https://www.hivejournal.com/**   https://hivejournal.com/**
    https://www.graphene.fm/**        https://graphene.fm/**
    https://www.write.cafe/**         https://write.cafe/**
    https://www.lovio.io/**           https://lovio.io/**
    https://www.dreampro.io/**        https://dreampro.io/**
    http://localhost:3000/**
    

    The www and bare-host entries are separate origins for cookie purposes, so both are needed unless you redirect one to the other at the DNS/Vercel layer. The localhost entry is for dev.

    Use /**, not just /auth/callback. OAuth only needs /auth/callback, but the same allowlist governs email confirmation (redirects to /dashboard, /lovio, …) and password reset (/auth/reset-password). Enumerating only /auth/callback works for Google but silently breaks the email-confirmation flow once it's enabled — the confirm link's /dashboard target isn't matched, Supabase falls back to the Site URL, and the user lands on the wrong host. The wildcard covers every flow. (See the email-link note in RESEND_SMTP_SUPABASE_SETUP.md.)

    Every branded rewrite domain needs its entries here. A host can be wired into the frontend (middleware.ts rewrite) and backend (PLATFORM_ORIGINS CORS) yet still be broken for auth if it's missing from this allowlist — Supabase falls back to the hivejournal.com Site URL, the session never lands on the originating host, and the client-side /dashboard guard bounces every signup to /auth/signin. This is exactly how lovio.io shipped: 100% of its signups bounced and 0 activated until it was added here. When you add a domain to MULTI_BRAND_DOMAINS.md, add it to this list and to Authorized domains above in the same change.

  3. Click Save.

Common mistake: only adding https://www.<brand>.com/auth/callback. A user who visits the bare host gets a Site URL fallback and the session lands on the wrong domain. The PKCE code-verifier cookie was set on the originating host, so the wrong-domain callback can't decode the code → "invalid request: both auth code and code verifier should be non-empty."


4. (Optional) Enable manual identity linking

If you want the "Link Google" button on /dashboard/settings to actually attach a Google identity to an existing email-password user (instead of erroring), enable manual linking:

  1. Authentication → Settings.
  2. Find Manual linking enabled and toggle it ON.
  3. Save.

Without this, supabase.auth.linkIdentity() returns an actionable in-card error explaining the missing config. The OAuth signin / signup paths still work fine without it — only the link-from-settings affordance requires it.


5. Smoke test

  1. Visit https://www.hivejournal.com/auth/signin (or https://www.write.cafe/auth/signin, etc.).
  2. Click Continue with Google.
  3. Pick a Google account. You should be redirected back to the brand domain's /auth/callback, then to /dashboard (or /graphene / /write-cafe), signed in.
  4. From /dashboard/settings, the Sign-in methods card should show both Email + password ✓ Connected and Google ✓ Connected.

If something goes wrong, the symptoms map to causes:

SymptomLikely cause
Lands on hivejournal.com instead of the brand domain you started onBrand-domain /auth/callback URL missing from Supabase Redirect URLs allowlist
"Sign-in failed: invalid request: both auth code and code verifier should be non-empty"Same as above — Supabase fell back to Site URL and the PKCE cookie was set on the originating host
"Account linking is not enabled on this project"Manual linking not turned on in Supabase Auth → Settings
"An account with this email already exists" notice on /auth/signinWorking as intended — the existing email-password user is being routed to sign in with their password, then link Google from settings (security floor — prevents OAuth-based takeover of unverified accounts)
Google sign-in works on hivejournal.com but not write.cafeSame allowlist issue scoped to a specific brand
GOOGLE OAUTH SETUP — Docs | HiveJournal