Techtrekking

How to Add "Login with Google" to Your Next.js App Using Better Auth

By Pravin•

How to Add "Login with Google" to Your Next.js App Using Better Auth

Adding social authentication improves user experience by removing the friction of creating and remembering new passwords. In this guide, you will learn how to implement Login with Google in a Next.js (App Router) application using Better Auth—the modern, type-safe authentication framework for TypeScript—configured for both your live production domain (https://example.com) and local development (http://localhost:3000).

Prerequisites

Before we begin, make sure you have:

  • Node.js (v18.17 or later) installed.
  • A Next.js project using the App Router (src/app or app directory).
  • A database connected with Prisma (PostgreSQL, MySQL, or SQLite). Note: Better Auth also supports Drizzle, Kysely, or direct database connections.
  • A Google account to access the Google Cloud Console.
  • Your production domain ready (https://example.com).

Step 1: Set Up Google OAuth Credentials

To allow users to sign in with Google, you need to register your application in the Google Cloud Console to obtain a Client ID and Client Secret. You can configure both your production domain and local environment in the same OAuth client.

  1. Go to the Google Cloud Console.
  2. Click the project dropdown at the top left and select New Project. Give it a name (e.g., Example App Auth) and click Create.
  3. Navigate to APIs & Services > OAuth consent screen (or Google Auth Platform > Branding / Audience in the updated console) in the left sidebar:
    • Choose External and click Create.
    • Fill in your App name, User support email, Authorized domains (add example.com), and Developer contact information.
    • Save and continue through the steps.
    • When you are ready for public users on example.com, set the publishing status to In production so it isn't restricted to test users.
  4. Navigate to APIs & Services > Credentials (or Google Auth Platform > Clients):
    • Click + Create Credentials and select OAuth client ID.
    • Select Web application as the Application type.
    • Under Authorized JavaScript origins, add both your production domain and your local reference:
      https://example.com http://localhost:3000
    • Under Authorized redirect URIs, add the callback URLs for both environments (Better Auth uses /api/auth/callback/google by default):
      https://example.com/api/auth/callback/google http://localhost:3000/api/auth/callback/google
    • Click Create and copy your Client ID and Client Secret.

Step 2: Install Better Auth

In your Next.js project terminal, install better-auth:

npm install better-auth

Step 3: Configure Environment Variables

Add the required environment variables to your .env (or .env.local) file for local development, and configure the production values on your hosting provider (e.g., Vercel, VPS, or Docker environment).

Generate a secure BETTER_AUTH_SECRET by running npx @better-auth/cli@latest secret in your terminal:

# Generate via: npx @better-auth/cli@latest secret BETTER_AUTH_SECRET="your-super-secret-random-string" # Use http://localhost:3000 locally, and https://example.com in production BETTER_AUTH_URL="http://localhost:3000" NEXT_PUBLIC_APP_URL="http://localhost:3000" # Google OAuth Credentials GOOGLE_CLIENT_ID="your-google-client-id.apps.googleusercontent.com" GOOGLE_CLIENT_SECRET="your-google-client-secret"

Production Note: When deploying to example.com, set BETTER_AUTH_URL="https://example.com" and NEXT_PUBLIC_APP_URL="https://example.com" in your production environment variables.

Step 4: Create the Better Auth Server Instance

Create a new file at src/lib/auth.ts (or lib/auth.ts if you don't use a src/ folder). Here, we connect Better Auth to Prisma and enable the Google social provider.

// src/lib/auth.ts import { betterAuth } from "better-auth"; import { prismaAdapter } from "better-auth/adapters/prisma"; import { nextCookies } from "better-auth/next-js"; import { prisma } from "@/lib/prisma"; // Your existing PrismaClient instance export const auth = betterAuth({ baseURL: process.env.BETTER_AUTH_URL, trustedOrigins: [ "https://example.com", "http://localhost:3000", ], database: prismaAdapter(prisma, { provider: "postgresql", // Change to "mysql" or "sqlite" if needed }), socialProviders: { google: { clientId: process.env.GOOGLE_CLIENT_ID as string, clientSecret: process.env.GOOGLE_CLIENT_SECRET as string, }, }, plugins: [ nextCookies(), // Ensures cookies work properly with Next.js Server Actions ], });

Step 5: Generate Database Tables with the Better Auth CLI

Better Auth stores users, sessions, and OAuth account links in your database for safe, revocable session management. Run the Better Auth CLI to automatically add the required models (User, Session, Account, Verification) to your schema.prisma file:

npx @better-auth/cli@latest generate

Once the schema is updated, push or migrate the changes to your database:

npx prisma migrate dev --name add-better-auth

Step 6: Set Up the API Route Handler

Create a catch-all API route handler so Better Auth can process /api/auth/* requests (including Google's OAuth callback).

Create src/app/api/auth/[...all]/route.ts:

// src/app/api/auth/[...all]/route.ts import { auth } from "@/lib/auth"; import { toNextJsHandler } from "better-auth/next-js"; export const { GET, POST } = toNextJsHandler(auth);

Step 7: Create the Better Auth Client

Create a client-side helper file at src/lib/auth-client.ts to trigger sign-in, sign-out, and reactive session hooks from Client Components:

// src/lib/auth-client.ts import { createAuthClient } from "better-auth/react"; export const authClient = createAuthClient({ baseURL: process.env.NEXT_PUBLIC_APP_URL, });

Step 8: Build the Sign-In and Sign-Out Components

Create a Client Component file at src/components/auth-buttons.tsx that triggers Google OAuth using authClient.signIn.social:

// src/components/auth-buttons.tsx "use client"; import { useState } from "react"; import { useRouter } from "next/navigation"; import { authClient } from "@/lib/auth-client"; export function SignInButton() { const [loading, setLoading] = useState(false); const handleGoogleSignIn = async () => { setLoading(true); await authClient.signIn.social({ provider: "google", callbackURL: "/", // Where to redirect after successful login }); }; return ( <button onClick={handleGoogleSignIn} disabled={loading} className="px-4 py-2 font-semibold text-white bg-blue-600 rounded-lg hover:bg-blue-700 disabled:opacity-50 transition" > {loading ? "Redirecting..." : "Sign in with Google"} </button> ); } export function SignOutButton() { const router = useRouter(); const handleSignOut = async () => { await authClient.signOut({ fetchOptions: { onSuccess: () => { router.refresh(); // Refresh Server Components to reflect signed-out state }, }, }); }; return ( <button onClick={handleSignOut} className="px-4 py-2 font-semibold text-gray-800 bg-gray-200 rounded-lg hover:bg-gray-300 transition" > Sign Out </button> ); }

Step 9: Read the Session in a Server Component

In your Next.js App Router pages (src/app/page.tsx), you can securely fetch the user's session on the server by passing the incoming request headers() to auth.api.getSession:

// src/app/page.tsx import { headers } from "next/headers"; import { auth } from "@/lib/auth"; import { SignInButton, SignOutButton } from "@/components/auth-buttons"; export default async function Home() { const session = await auth.api.getSession({ headers: await headers(), }); return ( <main className="flex min-h-screen flex-col items-center justify-center p-24"> <div className="max-w-md w-full bg-white p-8 rounded-xl shadow-md text-center space-y-6"> <h1 className="text-2xl font-bold text-gray-900"> Next.js + Better Auth </h1> {session?.user ? ( <div className="space-y-4"> {session.user.image && ( <img src={session.user.image} alt={session.user.name || "User Avatar"} className="w-16 h-16 rounded-full mx-auto border" /> )} <div> <p className="text-lg font-medium text-gray-800"> Welcome, {session.user.name}! </p> <p className="text-sm text-gray-500">{session.user.email}</p> </div> <SignOutButton /> </div> ) : ( <div className="space-y-4"> <p className="text-gray-600">You are currently signed out.</p> <SignInButton /> </div> )} </div> </main> ); }

Step 10: Test Locally and Deploy to example.com

Local Reference Testing (http://localhost:3000)

  1. Make sure BETTER_AUTH_URL="http://localhost:3000" and NEXT_PUBLIC_APP_URL="http://localhost:3000" are set in your local .env.
  2. Start your dev server with npm run dev and visit http://localhost:3000.
  3. Click Sign in with Google—you will be redirected through Google and back to http://localhost:3000/api/auth/callback/google.

Going Live on https://example.com

  1. Update your production environment variables on your server/host:
    BETTER_AUTH_URL="https://example.com" NEXT_PUBLIC_APP_URL="https://example.com"
  2. Ensure https://example.com and https://example.com/api/auth/callback/google are listed in your Google Cloud OAuth Client.
  3. Confirm your Google OAuth consent screen is published (In production) so any user can sign in on https://example.com.
Comments
No comments yet. Be the first to comment!
Leave a Comment
Your comment will be visible after approval.