How to implement Authententication with AuthJS v5 (Next-Auth) using Google OAuth

Hi! I strugled 2 days on implementing basic Authentication using AuthJs v5 library with Google OAuth for Nextjs application. So. i thought be good to show how to make it and use it for reference. Many thing will come up from documentation. I assume that you intialized next project already.

 

Table of Contents

Install AuthJs v5

Install library

npm install next-auth@beta

Add Auth environment variable

npx auth secret
Add generated string to .env file
AUTH_SECRET="Your generated secret"

Create auth.js / auth.ts (if you use Typescript)

import NextAuth from "next-auth"
import Google from "next-auth/providers/google"
 
export const { handlers, signIn, signOut, auth } = NextAuth({
  providers: [Google],
})

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

 Add in route:
import { handlers } from "@/auth"
export const { GET, POST } = handlers

Add middleware.js / .ts

export { auth as middleware } from "@/auth"

// Don't invoke middleware in some paths
export const config = {
    matcher: ["/((?!api|_next/static|_next/image|favicon.ico).*)"],
  }

Set-up Google OAuth

Create project on Google developers console

Create project on Google Developer Console in OAuth Consent screen.

You need Client ID and Client Screen and add http://localhost:3000/api/auth/callback/google to Authrised redirect Uri's 

(See photo below)

Google Developer screenshot

Add ID and Secret to .env file

AUTH_GOOGLE_ID={CLIENT_ID}
AUTH_GOOGLE_SECRET={CLIENT_SECRET}

Add this variables to your .env file

How to use sign in and sign out

Using server-side component (non interactive)

Sign In

import { signIn } from "@/auth"
 
export default function SignIn() {
  return (
    <form
      action={async () => {
        "use server"
        await signIn("google")
      }}
    >
      <button type="submit">Signin with Google</button>
    </form>
  )
} 

Sign Out same as Sign in

import { signOut } from "@/auth"
 
export default function SignOut() {
  return (
    <form
      action={async () => {
        "use server"
        await signOut();
      }}
    >
      <button type="submit">Sign Out</button>
    </form>
  )
} 

Using client side component ("use client",  interactive page)

Sign In

"use client";
import { signIn } from "next-auth/react";

const SignIn = () => {
  const handleClick = async () => {
    await signIn("google");
  };

  return (
      <button className="btn" onClick={handleClick}>
        Sign In
      </button>
  );
};

export default SignIn;

Sign Out same as Sign in

"use client";

const SignOut = () => {
  const handleClick = async () => {
    await signOut();
  };

  return (
      <button onClick={handleClick} className="btn">
        Sign Out
      </button>
  );
};

export default SignOut;

How to protect route

Add Session Provider to your Layout, to have access to data

import "@/styles/globals.css";
import { auth } from "@/auth";
import { SessionProvider } from "next-auth/react";

export const metadata = {
  title: "Project",
  description: "Project",
};

export default async function RootLayout({ children }) {
  const session = await auth();
  return (
    <html lang="en">
      <body>
        <SessionProvider session={session}>
          <main>{children}</main>
        </SessionProvider>
      </body>
    </html>
  );
}

Add redirect if user not authenticated. 

"use client";

import { redirect } from "next/navigation";
import { useSession } from "next-auth/react";

const ProtectedRoute = () => {
  const { data: session } = useSession();
  if (!session) return redirect("/login");

  return (
    <div>
      This is protected route
    </div>
  );
};

export default ProtectedRoute;

That's it.

Â