In this tutorial, we'll build a Next.js application and authenticate it with Strapi 5 and NextAuth. The goal is to demonstrate Next.js authentication with NextAuth and Strapi headless CMS.
Strapi CMS is the leading open-source headless CMS. It is 100% JavaScript, fully customizable, and developer-first. Its excellent developer experience has helped me build prototypes and products more efficiently.
Next.js is a React framework for building server-side rendered applications. It offers numerous features, a superior developer experience, and native TypeScript support.
NextAuth is an authentication library designed for Next.js authentication. It is straightforward, rapid, and secure.
The tutorial's code is available on GitHub.
To create a new Next.js application, use the following command in your working directory:
1yarn create next-app
Configure your Next app as follows:
1✔ What is your project named? … frontend
2✔ Would you like to use TypeScript? … No
3✔ Would you like to use ESLint? … No
4✔ Would you like to use Tailwind CSS? … Yes
5✔ Would you like your code inside a `src/` directory? … No
6✔ Would you like to use App Router? (recommended) … No
7✔ Would you like to use Turbopack for `next dev`? … Yes
8✔ Would you like to customize the import alias (`@/*` by default)? … No
After setup, run:
1cd frontend && yarn dev
This starts the application at localhost:3000.
Open up your working directory in a new terminal session and create a new Strapi project named backend
.
1npx create-strapi-app@latest backend --quickstart
After setup, open the administration panel at localhost:1337/admin.
Create an administrator using the registration form.
After creating the first administrator, you'll be logged into the Strapi administration panel:
This section covers creating and integrating a Google OAuth Client.
Begin by accessing the Google Developer Console.
To create an OAuth client ID, first configure your consent screen by clicking Configure Consent Screen.
Click Get Started to configure your application's identity and manage Google API credentials.
Configure project settings: App Name, Support Email, Audience (External), and Contact Information.
When prompted that no OAuth clients exist, click CREATE OAUTH CLIENT.
Configure the OAuth client ID:
Web application
as the application type.http://localhost:3000/api/auth/callback/google
http://localhost:1337/api/connect/google/callback
After clicking CREATE, obtain the OAuth Client credentials.
View and download OAuth credentials on the OAuth 2.0 Client IDs page.
Download OAuth Client
reveals the Client ID
and Client Secret
.
Download the JSON file.
1{
2 "web": {
3 "client_id": "YOUR_CLIENT_ID",
4 "project_id": "strapi-nextjs-auth",
5 "auth_uri": "https://accounts.google.com/o/oauth2/auth",
6 "token_uri": "https://oauth2.googleapis.com/token",
7 "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
8 "client_secret": "YOUR_CLIENT_SECRET",
9 "redirect_uris": [
10 "http://localhost:3000/api/auth/callback/google",
11 "http://localhost:1337/api/connect/google/callback"
12 ]
13 }
14}
Copy the client_id
and the client_secret
Create a .env
file in the frontend
directory to store credentials:
1NEXT_PUBLIC_API_URL=http://localhost:1337/api
2NEXTAUTH_SECRET=supersecret
3NEXTAUTH_URL=http://localhost:3000
4GOOGLE_CLIENT_ID="4692723930384-jkdy095fj948953ld98450f754d.apps.googleusercontent.com"
5GOOGLE_CLIENT_SECRET="G0CV556-4y9ic9ya8jdi9"
Replace the GOOGLE_CLIENT_ID
and GOOGLE_CLIENT_SECRET
with credentials from your new Google OAuth Client.
Next, add these credentials to the Strapi application. In the Strapi administration panel, add the Google OAuth Client credentials and enable the Google provider within the Providers menu in the Settings tab.
Enter the Client ID and Client Secret in the Google provider and enable it:
In this section, we'll install and integrate NextAuth. NextAuth is an open-source authentication solution for Next.js applications.
Run the following command in the frontend
directory to install NextAuth:
1yarn add next-auth
Create a new file, [...nextauth].js
, in the frontend/pages/api/auth
directory with the following content:
1// frontend/pages/api/auth/[...nextauth].js
2import NextAuth from "next-auth"
3import GoogleProvider from "next-auth/providers/google"
4
5export const authOptions = {
6 providers: [
7 GoogleProvider({
8 clientId: process.env.GOOGLE_CLIENT_ID,
9 clientSecret: process.env.GOOGLE_CLIENT_SECRET,
10 }),
11 ],
12 secret: process.env.NEXTAUTH_SECRET,
13 session: {
14 strategy: "jwt",
15 },
16 callbacks: {
17 async session({ session, token, user }) {
18 if (token) {
19 session.jwt = token.jwt;
20 session.id = token.id;
21 }
22 return session;
23 },
24 async jwt({ token, user, account }) {
25 if (account && user) {
26 try {
27 const response = await fetch(
28 `${process.env.NEXT_PUBLIC_API_URL}/auth/${account.provider}/callback?access_token=${account.access_token}`
29 );
30 const data = await response.json();
31 token.jwt = data.jwt;
32 token.id = data.user.id;
33 } catch (error) {
34 console.error("Error in JWT callback:", error);
35 }
36 }
37 return token;
38 }
39 }
40}
41
42export default NextAuth(authOptions)
In the NextAuth callback, call the Strapi Authentication API endpoint. Store the JWT (token.jwt
) and user ID (data.user.id
) from the Strapi API response.
This identifies the currently authenticated user.
Retrieve authenticated user details using NextAuth's getSession function. No returned details indicate the user is not authenticated.
Verify NextAuth functionality by updating frontend/pages/index.js
:
1 // frontend/pages/index.js
2import { getSession, signIn, signOut } from "next-auth/react";
3import Head from 'next/head';
4import Link from "next/link";
5import React from "react";
6
7const IndexPage = ({
8 session,
9}) => {
10 const signInButtonNode = () => {
11 if (session) {
12 return false;
13 }
14
15 return (
16 <div className="w-full flex justify-end p-4">
17 <Link href="/api/auth/signin" className="w-full max-w-xs">
18 <button
19 className="w-full bg-blue-500 hover:bg-blue-600 text-white font-bold py-2 px-4 rounded transition-colors duration-300"
20 onClick={(e) => {
21 e.preventDefault();
22 signIn();
23 }}
24 >
25 Sign In
26 </button>
27 </Link>
28 </div>
29 );
30 };
31
32 const signOutButtonNode = () => {
33 if (!session) {
34 return false;
35 }
36
37 return (
38 <div className="w-full flex justify-end p-4">
39 <Link href="/api/auth/signout" className="w-full max-w-xs">
40 <button
41 className="w-full bg-red-500 hover:bg-red-600 text-white font-bold py-2 px-4 rounded transition-colors duration-300"
42 onClick={(e) => {
43 e.preventDefault();
44 signOut();
45 }}
46 >
47 Sign Out
48 </button>
49 </Link>
50 </div>
51 );
52 };
53
54 if (!session) {
55 return (
56 <div className="min-h-screen bg-gray-100 flex flex-col items-center justify-center">
57 <div className="w-full max-w-md bg-white shadow-md rounded-lg p-6">
58 <div className="navbar mb-4">
59 {signOutButtonNode()}
60 {signInButtonNode()}
61 </div>
62 <div className="text text-center text-red-500 font-semibold">
63 You aren't authorized to view this page
64 </div>
65 </div>
66 </div>
67 )
68 }
69
70 return (
71 <div className="min-h-screen bg-gray-100 flex flex-col items-center justify-center">
72 <Head>
73 <title>Index Page</title>
74 </Head>
75 <div className="w-full max-w-md bg-white shadow-md rounded-lg p-6">
76 <div className="navbar mb-4">
77 {signOutButtonNode()}
78 {signInButtonNode()}
79 </div>
80 <div className="text text-center text-green-500 font-semibold">
81 Hello world
82 </div>
83 </div>
84 </div>
85 );
86};
87
88export const getServerSideProps = async ({ req }) => {
89 const session = await getSession({ req });
90 return {
91 props: {
92 session,
93 },
94 };
95};
96
97export default IndexPage;
Upon visiting localhost:3000, you'll see the sign-in page.
Click Sign In and log in with your Google account. After authentication, you'll see the protected page.
Authenticated user details are available in the page's session prop.
Fetch user details from the session prop. The authenticated user will appear in the Strapi administration panel.
The complete code for this tutorial is available on GitHub.
This tutorial demonstrated Next.js authentication using Strapi 5 and NextAuth via the REST API. A similar approach can be applied to GraphQL.
Start with Strapi using the Strapi docs or live demo.
Nirmalya is a Developer, who likes designing, writing and building Open Source stuffs.
Mark Munyaka is a freelance web developer and writer who loves problem-solving and testing out web technologies. You can follow him on Twitter @McMunyaka