Integrate Google Authentication in your Next Project?

Vishal SharmaVishal Sharma
10 min read

You're building the next big thing. Your app idea is solid, your code is clean, but then reality hits—you need user authentication. Suddenly you're googling "password hashing best practices" at 2 AM, wondering if bcrypt is still cool or if you should use Argon2. Your simple login form turns into a security minefield of password requirements, email verification, password resets, and don't even get started on "forgot password" flows.

Sound familiar?

Here's the thing—while you're building custom auth systems, your competitors are shipping features. They're using Google Authentication and focusing on what actually makes their product unique.

How to Integrate Google Authentication?

I'll be honest—it might seem overwhelming at first glance. Authentication, OAuth flows, credentials, APIs... it sounds like a lot. But here's the thing: after reading this blog, implementing Google Auth will be so straightforward that you'll wonder why you ever considered building custom authentication.

Here's our game plan:

  1. Get Google's permission (set up credentials - 5 minutes)

  2. Install one package (literally one npm install)

  3. Write minimal code (mostly copy-paste)

  4. Test and celebrate (watch it work like magic)

The secret sauce? We're not building authentication—we're just connecting to Google's existing system. They've done the heavy lifting; we're just plugging in.

Step 1: Getting Google's Permission (The Credential Dance)

Before we jump into code, we need to introduce our app to Google. Think of this like getting a visitor's badge at a secure building—Google needs to know who you are and where to send users after they log in.

What you need: A Google account (you definitely have one)

1. Create Your Project in Google Cloud Console

Navigate to: Google Cloud Console

First time here? Don't panic. Google Cloud Console looks intimidating, but we're only using a tiny corner of it.

  • Click the "Select a project" dropdown at the top

  • Click "New Project"

  • Project name: Give it something meaningful like "my-app-auth" or "todo-app-google-auth"

  • Organization: Leave as default (usually your Gmail account)

  • Click "Create"

2. Enable the Google Identity API

Why this step? Google has hundreds of APIs. We need to specifically tell Google we want to use their identity/authentication API.

  • In the left sidebar, click "APIs & Services""Library"

  • In the search bar, type "Google Identity"

  • Click on "Google Identity Services API"

  • Click the blue "Enable" button

What's this? This is the screen users see when they click "Sign in with Google." You know, the one that says "MyApp wants to access your basic profile info."

  • Go to "APIs & Services""OAuth consent screen"

  • Choose "External" (unless you're building for a specific Google Workspace)

  • Click "Create"

Fill out the required fields:

  • App name: Your app's name (users will see this)

  • User support email: Your email

  • Developer contact information: Your email again

Pro tip: You can leave most other fields blank for now. Click "Save and Continue" through the next screens.

4. Create Your OAuth Credentials (The Important Part)

This is where we get the secret keys that let our app talk to Google.

  • Go to "APIs & Services""Credentials"

  • Click "+ Create Credentials""OAuth client ID"

  • Application type: Choose "Web application"

  • Name: Something like "MyApp Web Client"

Now the crucial part - Authorized redirect URIs:

For development (add both):

http://localhost:3000/api/auth/callback/google
http://localhost:3001/api/auth/callback/google

For production (add your actual domain):

https://yourapp.com/api/auth/callback/google
https://www.yourapp.com/api/auth/callback/google

Why multiple URIs? Different ports for development, and you might use both www and non-www versions in production.

Click "Create"

5. Save Your Credentials (Guard These With Your Life)

After clicking create, you'll see a popup with your credentials:

Client ID: 123456789-abcdefghijklmnop.apps.googleusercontent.com
Client Secret: GOCSPX-your_super_secret_key_here

Copy these immediately and save them somewhere safe. We'll need them in our code.

Security warning: These credentials are like your house keys. Never commit them to GitHub or share them publicly. Treat the Client Secret especially carefully—it's literally the secret that proves your app is legitimate.

Step 2 : Initialize a Next.js Project in your local.

I hope you already know this and for that reason I am not going for it and just going on the next step but if you are already done with it then make a .env file to store the environment variables in it and don’t push it to the prod or github otherwise it could be misused.

and now install the next auth to make the magic begins and here is the actual thing works.It might feel complicated but trust me I will make it super easy for you.

npm install next-auth

Step 3 : Create your authentication configuration (App Router)

Create /app/api/auth/[...nextauth]/route.js:

But why we are doing this so first of all the brackets […nextauth] handles all the dynamic routes in our project like:

/api/auth/signin
/api/auth/signout  
/api/auth/callback/google
/api/auth/session
/api/auth/csrf
/api/auth/providers

and now lets write the route.js

import NextAuth from 'next-auth'
import GoogleProvider from 'next-auth/providers/google'

const handler = NextAuth({
  providers: [
    GoogleProvider({
      clientId: process.env.client_id,
      clientSecret: process.env.client_secret,
    })
  ],
  callbacks: {
    async session({ session, token }) {
      // Add user ID to session
      session.accessToken = token.accessToken
      return session
    },
    async jwt({ token, account }) {
      if (account) {
        token.accessToken = account.access_token
      }
      return token
    }
  }
})


export { handler as GET, handler as POST }
export { handler as GET, handler as POST }

This tells Next.js: "Use this handler for both GET and POST requests to any URL that matches /api/auth/*"

Now let’s make a SessionProvider which is similar to Context API and helps us to derive the user information all around the application.

/app/provider.jsx

'use client'
import { SessionProvider } from 'next-auth/react'

export function Providers({ children, session }) {
  return (
    <SessionProvider session={session}>
      {children}
    </SessionProvider>
  )
}

After this just wrap the application in it by changing the root layout

import Providers from './provider';
..
..
export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body
        className={`${geistSans.variable} ${geistMono.variable} antialiased`}
      >
        <Providers>
        {children}
        </Providers>

      </body>
    </html>
  );
}

Step 4 : Handling Protected Routes

We can handle protected routes, such as the dashboard or other pages that should only be accessible to subscribed users, by checking the session on those pages.

If we only need to verify whether the user is logged in, the implementation is straightforward. However, if we also need to check whether the user is subscribed, we can include that information in the session or token for use in later stages.

For now, let's make a basic Dashboard page and ensure it is inaccessible to unauthenticated users.

app/dashboard/page.jsx

import { getServerSession } from 'next-auth'
import { redirect } from 'next/navigation'
import Navbar from '../components/Navbar'

export default async function DashboardPage() {
  const session = await getServerSession()

  // Server-side protection
  if (!session) {
    redirect('/login')
  }

  return (
    <div className="min-h-screen bg-gray-50">
      <Navbar session={session} />

      <main className="max-w-7xl mx-auto px-4 py-8">
        <div className="mb-8">
          <h1 className="text-3xl font-bold text-gray-900">
            Welcome back, {session.user.name?.split(' ')[0]}! 👋
          </h1>
          <p className="text-gray-600 mt-2">
            Here's what's happening with your tasks today.
          </p>
        </div>

        {/* Dashboard Stats */}
        <div className="grid grid-cols-1 md:grid-cols-4 gap-6 mb-8">
          <div className="bg-white p-6 rounded-lg shadow-sm">
            <div className="flex items-center">
              <div className="flex-shrink-0">
                <div className="w-8 h-8 bg-blue-500 rounded-full flex items-center justify-center">
                  <span className="text-white text-sm font-medium">📋</span>
                </div>
              </div>
              <div className="ml-4">
                <p className="text-sm font-medium text-gray-600">Total Tasks</p>
                <p className="text-2xl font-semibold text-gray-900">24</p>
              </div>
            </div>
          </div>

          <div className="bg-white p-6 rounded-lg shadow-sm">
            <div className="flex items-center">
              <div className="flex-shrink-0">
                <div className="w-8 h-8 bg-green-500 rounded-full flex items-center justify-center">
                  <span className="text-white text-sm font-medium"></span>
                </div>
              </div>
              <div className="ml-4">
                <p className="text-sm font-medium text-gray-600">Completed</p>
                <p className="text-2xl font-semibold text-gray-900">18</p>
              </div>
            </div>
          </div>

          <div className="bg-white p-6 rounded-lg shadow-sm">
            <div className="flex items-center">
              <div className="flex-shrink-0">
                <div className="w-8 h-8 bg-orange-500 rounded-full flex items-center justify-center">
                  <span className="text-white text-sm font-medium"></span>
                </div>
              </div>
              <div className="ml-4">
                <p className="text-sm font-medium text-gray-600">In Progress</p>
                <p className="text-2xl font-semibold text-gray-900">4</p>
              </div>
            </div>
          </div>

          <div className="bg-white p-6 rounded-lg shadow-sm">
            <div className="flex items-center">
              <div className="flex-shrink-0">
                <div className="w-8 h-8 bg-red-500 rounded-full flex items-center justify-center">
                  <span className="text-white text-sm font-medium">🔥</span>
                </div>
              </div>
              <div className="ml-4">
                <p className="text-sm font-medium text-gray-600">Overdue</p>
                <p className="text-2xl font-semibold text-gray-900">2</p>
              </div>
            </div>
          </div>
        </div>

        {/* Recent Tasks */}
        <div className="bg-white rounded-lg shadow-sm">
          <div className="px-6 py-4 border-b border-gray-200">
            <h2 className="text-lg font-semibold text-gray-900">Recent Tasks</h2>
          </div>
          <div className="divide-y divide-gray-200">
            {[
              { id: 1, title: 'Review pull request #124', status: 'completed', priority: 'high' },
              { id: 2, title: 'Update user documentation', status: 'in-progress', priority: 'medium' },
              { id: 3, title: 'Fix login bug', status: 'pending', priority: 'high' },
              { id: 4, title: 'Design new landing page', status: 'in-progress', priority: 'low' },
            ].map((task) => (
              <div key={task.id} className="px-6 py-4 flex items-center justify-between">
                <div className="flex items-center">
                  <div className={`w-3 h-3 rounded-full mr-3 ${
                    task.status === 'completed' ? 'bg-green-500' :
                    task.status === 'in-progress' ? 'bg-orange-500' : 'bg-gray-300'
                  }`}></div>
                  <span className="text-gray-900">{task.title}</span>
                </div>
                <div className="flex items-center space-x-2">
                  <span className={`px-2 py-1 text-xs rounded-full ${
                    task.priority === 'high' ? 'bg-red-100 text-red-800' :
                    task.priority === 'medium' ? 'bg-orange-100 text-orange-800' :
                    'bg-gray-100 text-gray-800'
                  }`}>
                    {task.priority}
                  </span>
                  <span className="text-sm text-gray-500 capitalize">{task.status}</span>
                </div>
              </div>
            ))}
          </div>
        </div>
      </main>
    </div>
  )
}

I know it might be big code snippet for you but for your task you only have to check this below code

import { getServerSession } from 'next-auth'
import { redirect } from 'next/navigation'
import Navbar from '../components/Navbar'

export default async function DashboardPage() {
  const session = await getServerSession()

  // Server-side protection
  if (!session) {
    redirect('/login')
  }

To get the server session on the server page you can use getServerSession() which would have the information related to user like image,username,email (from google) and other information (token in our case) that we put it inside at next auth route.

Now lets try the basic way to handle login and signup correctly

app/login/page.jsx

'use client'
import { useSession, signIn } from 'next-auth/react'
import { useRouter } from 'next/navigation'
import { useEffect } from 'react'
import Link from 'next/link'

export default function LoginPage() {
  const { data: session, status } = useSession()
  const router = useRouter()

  // Redirect if already logged in
  useEffect(() => {
    if (session) {
      router.push('/dashboard')
    }
  }, [session, router])

  if (status === "loading") {
    return (
      <div className="min-h-screen flex items-center justify-center">
        <div className="text-lg">Loading...</div>
      </div>
    )
  }

  if (session) {
    return (
      <div className="min-h-screen flex items-center justify-center">
        <div className="text-lg">Redirecting to dashboard...</div>
      </div>
    )
  }

  return (
    <div className="min-h-screen bg-gray-50 flex flex-col justify-center py-12 sm:px-6 lg:px-8">
      <div className="sm:mx-auto sm:w-full sm:max-w-md">
        <Link href="/" className="flex justify-center">
          <h2 className="text-3xl font-bold text-blue-600">TaskMaster</h2>
        </Link>
        <h2 className="mt-6 text-center text-3xl font-extrabold text-gray-900">
          Welcome back
        </h2>
        <p className="mt-2 text-center text-sm text-gray-600">
          Sign in to your account to continue
        </p>
      </div>

      <div className="mt-8 sm:mx-auto sm:w-full sm:max-w-md">
        <div className="bg-white py-8 px-4 shadow sm:rounded-lg sm:px-10">
          <div className="space-y-6">
            <button
              onClick={() => signIn('google', { callbackUrl: '/dashboard' })}
              className="w-full flex justify-center items-center px-4 py-3 border border-gray-300 rounded-lg shadow-sm bg-white text-sm font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
            >
              <svg className="w-5 h-5 mr-3" viewBox="0 0 24 24">
                <path fill="#4285F4" d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"/>
                <path fill="#34A853" d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"/>
                <path fill="#FBBC05" d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"/>
                <path fill="#EA4335" d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"/>
              </svg>
              Continue with Google
            </button>

            <div className="mt-6">
              <div className="relative">
                <div className="absolute inset-0 flex items-center">
                  <div className="w-full border-t border-gray-300" />
                </div>
                <div className="relative flex justify-center text-sm">
                  <span className="px-2 bg-white text-gray-500">
                    Why Google Sign-In?
                  </span>
                </div>
              </div>
            </div>

            <div className="mt-6 text-sm text-gray-600 space-y-2">
              <div className="flex items-center">
                <span className="text-green-500 mr-2"></span>
                No passwords to remember
              </div>
              <div className="flex items-center">
                <span className="text-green-500 mr-2"></span>
                Secure Google authentication
              </div>
              <div className="flex items-center">
                <span className="text-green-500 mr-2"></span>
                Get started in seconds
              </div>
            </div>
          </div>
        </div>

        <div className="mt-6 text-center">
          <Link href="/" className="text-blue-600 hover:text-blue-500">
            ← Back to home
          </Link>
        </div>
      </div>
    </div>
  )
}

Instead of looking at all code what we are clearly looking for is , this one line which will do all the heavy lifting for us.

import { useSession, signIn } from 'next-auth/react'

  <button
       // just need to call the function on click.
              onClick={() => signIn('google', { callbackUrl: '/dashboard' })}
              className="w-full flex justify-center items-center px-4 py-3 border border-gray-300 rounded-lg shadow-sm bg-white text-sm font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
            >
              <svg className="w-5 h-5 mr-3" viewBox="0 0 24 24">
                <path fill="#4285F4" d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"/>
                <path fill="#34A853" d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"/>
                <path fill="#FBBC05" d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"/>
                <path fill="#EA4335" d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"/>
              </svg>
              Continue with Google
            </button>

similary you can signOut using the signOut() method with callbackUrl which tells where you will redirect the user after sign out.

Now, after this, you just need to build a homepage that uses these components and integrates authentication properly. I've already created one—check it out in this Github repo.

Once you're done, test the Google authentication and let me know what you think about the blog!

If you liked it, don’t forget to show some love ⭐ and stay tuned for next week—more awesome stuff is coming your way.

Happy coding! 🚀

10
Subscribe to my newsletter

Read articles from Vishal Sharma directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Vishal Sharma
Vishal Sharma

I am a developer from Surat who loves to write about DSA,Web Development, and Computer Science stuff.