src/components/auth/one-tap.tsx).
It uses FedCM, Google’s
newer browser API that doesn’t depend on third-party cookies — which means it’ll
keep working as Chrome phases those out.
Prerequisites
- Google OAuth already set up. One-Tap reuses the same
OAuth client, so
GOOGLE_CLIENT_IDmust already exist. - A
NEXT_PUBLIC_GOOGLE_CLIENT_IDenv var — the public mirror of the same ID. - HTTPS in production. (HTTP works on
localhostfor dev.)
Step-by-step setup
-
Mirror the client ID into the public env. Better Auth’s One-Tap plugin
needs the ID on the client too — add to
.env.local:Same value asGOOGLE_CLIENT_ID. It’s safe to expose; it’s a public identifier. -
Turn the feature on. In
src/config/site.ts: -
Confirm the component is mounted. It already lives in
src/app/layout.tsx(or the locale layout) inside theNextIntlClientProviderso it’s alive across every page. The component renders nothing — it just listens for an idle moment to callauthClient.oneTap(). -
Restart
pnpm dev. Public env vars are baked at build/dev start.
How it actually works
src/components/auth/one-tap.tsx is a 30-line 'use client' component:
/login and the One-Tap popup are independent —
both can be active at the same time. One-Tap just makes the home page lighter.
The matching client config is in src/lib/auth-client.ts:
autoSelect: false is deliberate — auto-signing someone in without their click is
exactly the kind of dark pattern you want to avoid, and Google penalises it on
accounts.google.com. Leave it off.
Verify it works
- Make sure you have a Google account signed in (in another tab) and you are not signed in to your vibestrap site.
- Open the home page in an incognito window with that Google session present.
- Within a second or two, the One-Tap card should slide in from the top-right.
- Click it — you’re signed in, no redirect.
accounts.google.com to
see whether the FedCM request was sent.
Common pitfalls
- Works locally, dead in production. Almost always missing
NEXT_PUBLIC_GOOGLE_CLIENT_IDin your hosting provider’s env config (Vercel, Netlify, etc.). Public env vars are baked at build time — set them, then redeploy. - HTTPS required. Production hosts must serve over HTTPS.
localhostis the one HTTP exception browsers allow. - Brave or Safari shows nothing. FedCM is gated behind a setting in Brave (Shields) and is still rolling out in Safari. Don’t treat the One-Tap as the only way in — keep the regular button.
- User has multiple Google accounts. Instead of an instant sign-in card, they see an account chooser. Same plugin, just a different UI from Google’s side — nothing to fix on your end.
- Card appears but click does nothing. Usually means your OAuth client’s authorized JavaScript origins don’t include the current host. Add it in the Google Cloud Console under your OAuth 2.0 Client ID → Authorized JavaScript origins.
Official docs
- One-Tap features overview — developers.google.com/identity/gsi/web/guides/features
- FedCM migration guide — developers.google.com/identity/gsi/web/guides/fedcm-migration
- Display the One-Tap prompt — developers.google.com/identity/gsi/web/guides/display-one-tap
- Better Auth One-Tap plugin — better-auth.com/docs/plugins/one-tap