A Complete Guide to Google Auth & One-Tap in Next.js Using Better Auth + MongoDB
Learn how to integrate Better Auth with Google Login and One Tap to create a smooth, modern authentication flow in your Next.js…
Wiki topics:
🌐 · Web Development
A Complete Guide to Google Auth & One-Tap in Next.js Using Better Auth + MongoDB
Learn how to integrate Better Auth with Google Login and One Tap to create a smooth, modern authentication flow in your Next.js application.
Lets get straight to the point.
1.Install the better auth package using Bun , Npm or what ever you want.
bun add better-auth
2.Create an auth object
// src/lib/auth.js
import mongoose from "mongoose";
import connectDB from "@/server/db";
import { betterAuth } from "better-auth";
import { mongodbAdapter } from "better-auth/adapters/mongodb";
import { oneTap } from "better-auth/plugins";
let dbInstance;
let clientInstance;
// Lazily initialize the MongoDB connection (prevents multiple connections)
const getMongoDBInstances = async () => {
if (!dbInstance || !clientInstance) {
await connectDB(); // ensures mongoose connection is created
clientInstance = mongoose.connection.getClient(); // get raw Mongo client
dbInstance = clientInstance.db(); // get DB instance
}
return { db: dbInstance, client: clientInstance };
};
const { db, client } = await getMongoDBInstances();
export const auth = betterAuth({
// MongoDB adapter — handles user, session, and account storage
database: mongodbAdapter(db, {
client,
collectionNames: {
user: "users",
session: "sessions",
account: "accounts",
},
}),
// Enable email + password login
emailAndPassword: {
enabled: true, // optional, can remove if only social auth is used
},
// Social provider: Google OAuth
socialProviders: {
google: {
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
// Normalize Google profile structure → Better Auth user fields
async profile(profile) {
return {
id: profile.id,
email: profile.email,
name: profile.name,
image: profile.picture,
};
},
},
},
// Session handling (7 days expiry)
session: {
expiresIn: 60 * 60 * 24 * 7, // refresh window
updateAge: 60 * 60 * 24, // extend session every 24h
cookieCache: {
enabled: true,
maxAge: 5 * 60, // tiny optimization for fewer DB reads
},
},
// How user fields map to your MongoDB schema
user: {
fields: {
email: "email",
name: "fullName", // maps to your schema field
image: "image",
},
modelName: "users", // points to the "users" collection
},
// Allowed frontend origins (required for One Tap)
trustedOrigins: [
process.env.NEXT_PUBLIC_BASE_URL,
"http://localhost",
],
// Public base URL of your app
baseURL: process.env.NEXT_PUBLIC_BASE_URL,
// Secret key for signing sessions/JWTs
secret: process.env.BETTER_AUTH_SECRET || process.env.JWT_SECRET,
appName: "YOUR APP NAME",
// Enable Google One Tap
plugins: [oneTap()],
});
3.Now Configure the API route
// src/app/api/auth/[...all]/route.js
import { auth } from "@/lib/auth";
import { toNextJsHandler } from "better-auth/next-js";
export const { GET, POST } = toNextJsHandler(auth);
4.Connect DB function + model design
// Simple function to connect to the databasae
import mongoose from "mongoose";
const connectDB = async () => {
if (mongoose.connection.readyState >= 1) return;
try {
await mongoose.connect(process.env.MONGODB_URI);
console.log("Connected to DB.");
} catch (error) {
console.error("Error connecting to DB:", error);
}
};
export default connectDB;
// User model
import mongoose from "mongoose";
const schema = new mongoose.Schema(
{
fullName: {
type: String,
required: true,
trim: true,
},
email: {
type: String,
unique: true,
required: true,
lowercase: true,
trim: true,
},
password: {
type: String,
default: "",
},
image: {
type: String,
},
googleId: {
type: String,
unique: true,
sparse: true,
},
},
{
timestamps: true,
}
);
export default mongoose.models.User || mongoose.model("User", schema);
5. Create Auth client
// src/lib/auth-client.js
import { createAuthClient } from "better-auth/react";
import { oneTapClient } from "better-auth/client/plugins";
const GOOGLE_CLIENT_ID = "YOUR_GOOGLE_CLIENT_ID";
export const authClient = createAuthClient({
baseURL: process.env.NEXT_PUBLIC_BASE_URL // your website url,
plugins: [
oneTapClient({
clientId: GOOGLE_CLIENT_ID,
autoSelect: true,
cancelOnTapOutside: false,
context: "signin",
uxMode: "popup",
promptOptions: {
baseDelay: 3000,
maxAttempts: 5,
},
}),
],
});
export const {
signIn,
signUp,
signOut,
useSession,
forgetPassword,
resetPassword,
verifyEmail,
requestPasswordReset,
} = authClient;
6. Use auth client to sign in or sign up users
await signIn.email({
email: "EMAIL@gmail.com",
password: "PASSWORD",
callbackURL: "/dashboard" , // after login
});
await signUp.email({
email: "EMAIL@gmail.com",
password: "PASSWORD",
callbackURL: "/dashboard" , // after login
});
// to login with google use
await signIn.social({
provider: "google",
callbackURL: "/dashboard" ,
});
MAKE SURE YOU HAVE THESE IN YOUR .env FILE
BETTER_AUTH_SECRET=mysecret -> Use some strong secret key
BETTER_AUTH_URL=http://localhost:3000 -> Your Website url
IMPLEMENT THE ONE TAP POPUP
"use client";
import { authClient, useSession } from "@/lib/auth-client";
import { useEffect, useRef } from "react";
const OneTap = () => {
const oneTapInitialized = useRef(false);
const { data, isPending } = useSession();
useEffect(() => {
// do not show the popup if the user is already logged in
if (data?.user || isPending || oneTapInitialized.current) return;
const triggerOneTap = async () => {
oneTapInitialized.current = true;
try {
await authClient.oneTap({
fetchOptions: {
onSuccess: (context) => {
if (context?.data?.user) {
window.location.reload();
}
},
onError: (context) => {
console.error("OneTap authentication failed:", context.error);
oneTapInitialized.current = false;
},
},
});
} catch (error) {
console.error("OneTap initialization failed:", error);
oneTapInitialized.current = false;
}
};
triggerOneTap();
}, [data?.user, isPending]);
return null;
};
export default OneTap;
Now use this OneTap component in your root layout and Thats it.
메타데이터
- post_id
- ebe2de45c691
- slug
- a-complete-guide-to-google-auth-one-tap-in-next-js-using-better-auth-mongodb-ebe2de45c691
- url
- https://medium.com/@amirjld/a-complete-guide-to-google-auth-one-tap-in-next-js-using-better-auth-mongodb-ebe2de45c691
- canonical_url
- https://medium.com/@amirjld/a-complete-guide-to-google-auth-one-tap-in-next-js-using-better-auth-mongodb-ebe2de45c691
- author_url
- https://medium.com/@amirjld
- status
- ok
- fetched_at
- 2026-06-12 18:14:10