docs/auth/social-providers.md
Google OAuth is configured out of the box. The flow redirects users to Google's consent screen, then back to your app where Better Auth creates or links the account.
Google OAuth credentials are set in apps/api/lib/auth.ts:
socialProviders: {
google: {
clientId: env.GOOGLE_CLIENT_ID,
clientSecret: env.GOOGLE_CLIENT_SECRET,
},
},
https://your-domain.com/api/auth/callback/google
http://localhost:5173/api/auth/callback/google.env.local:GOOGLE_CLIENT_ID=your-client-id.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=GOCSPX-your-client-secret
The GoogleLogin component in apps/app/components/auth/google-login.tsx handles the OAuth redirect:
const handleGoogleLogin = async () => {
// Clear stale session before OAuth redirect
queryClient.removeQueries({ queryKey: sessionQueryKey });
// OAuth redirects to /login which validates session and redirects to returnTo
const callbackURL = returnTo
? `/login?returnTo=${encodeURIComponent(returnTo)}`
: "/login";
const result = await auth.signIn.social({
provider: "google",
callbackURL,
});
};
The flow works as follows:
auth.signIn.social() redirects to Google's consent screen/api/auth/callback/googlecallbackURL (/login?returnTo=...)returnToThe returnTo parameter survives the OAuth round-trip by being encoded into the callbackURL. When the user lands back on /login, the search params schema validates and sanitizes the URL:
const searchSchema = z.object({
returnTo: z
.string()
.optional()
.transform((val) => {
const safe = getSafeRedirectUrl(val);
return safe === "/" ? undefined : safe;
})
.catch(undefined),
});
Only same-origin relative paths are accepted – absolute URLs and protocol-relative URLs (//evil.com) are rejected.
Better Auth supports 30+ OAuth providers. To add one:
1. Add server config in apps/api/lib/auth.ts:
socialProviders: {
google: { ... },
github: { // [!code ++]
clientId: env.GITHUB_CLIENT_ID, // [!code ++]
clientSecret: env.GITHUB_CLIENT_SECRET, // [!code ++]
}, // [!code ++]
},
2. Add env vars to apps/api/lib/env.ts and your .env.local.
3. Update the providers list in apps/app/lib/auth-config.ts:
oauth: {
providers: ["google", "github"] as const, // [!code ++]
},
4. Create a login button component following the GoogleLogin pattern – clear session cache, call auth.signIn.social({ provider: "github" }), handle errors.
5. Add the button to the MethodSelection component in auth-form.tsx.