In this tutorial, we'll be building a Next.js application and authenticate that with Strapi and NextAuth.
Introduction
Strapi is the leading open-source headless CMS. It's 100% Javascript, fully customizable, and developer-first. I've been using Strapi for some of my Open Source projects, and the developer experience is excellent. It has helped me build prototypes and products much faster.
Next.js is a React framework for building Server-side rendered applications. It has many features with a good developer experience and supports TypeScript out of the box.
NextAuth is an authentication library built for use with Next.js. It's easy, fast, and secure.
The code for this tutorial is available on GitHub.
Software Required to Run the Application
Creating a New Next.js Application
Let's start by creating a new Next.js application. We can create a Next.js application using the following command:
yarn create next-app
The above command will ask for the name of the project. We'll call it “frontend”.
Once the setup of the project and installing all dependencies are complete, we can go inside the frontend directory and start the application using the following command:
cd frontend && yarn dev
The above command will start the application on http://localhost:3000/.
Creating a New Strapi Application
In this section, we'll create a new Strapi application using Docker. More information about how to create a new Strapi application using Docker can be obtained from their repository. We'll use Postgres to do this.
We can create a new directory and name it “backend” in the root of our project. We can create a new file docker-compose.yml
inside the backend directory with the following content:
# backend/docker-compose.yml
version: '3'
services:
strapi:
container_name: strapi
image: strapi/strapi
environment:
- DATABASE_CLIENT=postgres
- DATABASE_HOST=db
- DATABASE_PORT=5432
- DATABASE_NAME=strapi
- DATABASE_USERNAME=strapi
- DATABASE_PASSWORD=strapi
ports:
- 1337:1337
volumes:
- ./app:/srv/app
depends_on:
- db
db:
container_name: postgres
image: postgres
restart: always
volumes:
- ./db:/var/lib/postgresql/data
ports:
- 5432:5432
environment:
POSTGRES_USER: strapi
POSTGRES_PASSWORD: strapi
POSTGRES_DB: strapi
Now, we need to start Docker and run the following command inside the backend directory to create our new Strapi application:
docker-compose up
- When running this image, Strapi will check if there is a project in the
/srv/app
folder of the container. If there is nothing, it will run the Strapi new command in the container/srv/app
folder.
Once the setup of our Strapi application is complete, we'll be able to view the administration panel at http://localhost:1337/admin.
Next, we'll need to create our first administrator in order to log into the Strapi administration panel:
Once we create our first administrator, we'll be logged into the Strapi administration panel:
Creating and Integrating Google OAuth Client into our Applications
In this section, we'll create a new Google OAuth Client and integrate it into Next.js and Strapi applications.
First, we'll need to visit the Google Developer Console to create a new OAuth Client and copy the credentials (Client ID and Client Secret) in our frontend/**.env**
file:
- Create a new OAuth client ID.
- Choose “web application” as the application type.
- Add the following authorized redirect URLs:
http://localhost:3000/api/auth/callback/google
http://localhost:1337/connect/google/callback
Once we click on the save button, we'll get our new OAuth Client's credentials. We can create a new file .env
inside our frontend directory to store all the credentials:
// frontend/.env
NEXT_PUBLIC_API_URL=http://localhost:1337
NEXT_PUBLIC_DATABASE_URL=postgres://strapi:strapi@localhost:5432/strapi?synchronize=true
NEXTAUTH_URL=http://localhost:3000
GOOGLE_CLIENT_ID="12345.apps.googleusercontent.com"
GOOGLE_CLIENT_SECRET="1234-567-9"
You'll need to replace the values of GOOGLE_CLIENT_ID
and GOOGLE_CLIENT_SECRET
with the values of your new Google OAuth Client.
Next, let's add these credentials to our Strapi application as well. In the Strapi administration panel, we need to add the Google OAuth Client credentials and enable the Google provider. The values can be added in the Providers menu inside the Settings tab.
We need to enter the Client ID and Client Secret in the Google provider and enable that:
Installing and Integrating NextAuth with Next.js and Strapi
In this section, we'll be installing and integrating NextAuth.
We can run the following command inside our frontend directory to install NextAuth as a dependency:
yarn add next-auth
Next, we'll need to create a new file, ...nextauth.js
, inside frontend/pages/api/auth
directory with the following content:
// frontend/pages/api/auth/[...nextauth].js
import NextAuth from "next-auth";
import Providers from "next-auth/providers";
const options = {
providers: [
Providers.Google({
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
}),
],
database: process.env.NEXT_PUBLIC_DATABASE_URL,
session: {
jwt: true,
},
callbacks: {
session: async (session, user) => {
session.jwt = user.jwt;
session.id = user.id;
return Promise.resolve(session);
},
jwt: async (token, user, account) => {
const isSignIn = user ? true : false;
if (isSignIn) {
const response = await fetch(
`${process.env.NEXT_PUBLIC_API_URL}/auth/${account.provider}/callback?access_token=${account?.accessToken}`
);
const data = await response.json();
token.jwt = data.jwt;
token.id = data.user.id;
}
return Promise.resolve(token);
},
},
};
const Auth = (req, res) =>
NextAuth(req, res, options);
export default Auth;
In the NextAuth callback function, we're calling the Strapi Authentication API endpoint. We're storing the JWT (token.jwt
) and user ID (data.user.id
) from the data that the Strapi API sends us.
In this way, we can understand which user is currently authenticated.
We can get the details of the authenticated users from the [getSession](https://next-auth.js.org/getting-started/client#getsession)
function of NextAuth. If the getSession
function doesn't return us any details, we can assume that the user is not authenticated.
We'll also need to add the pg package, so that NextAuth can connect to our database directly. We can install that package using the following command from our frontend directory:
yarn add pg
We can verify whether NextAuth is working with our application by updating our frontend/pages/index.js
with the following content:
// frontend/pages/index.js
import { getSession, signIn, signOut } from "next-auth/client";
import Head from 'next/head';
import Link from "next/link";
import React from "react";
const IndexPage = ({
session,
}) => {
const signInButtonNode = () => {
if (session) {
return false;
}
return (
<div>
<Link href="/api/auth/signin">
<button
onClick={(e) => {
e.preventDefault();
signIn();
}}
>
Sign In
</button>
</Link>
</div>
);
};
const signOutButtonNode = () => {
if (!session) {
return false;
}
return (
<div>
<Link href="/api/auth/signout">
<button
onClick={(e) => {
e.preventDefault();
signOut();
}}
>
Sign Out
</button>
</Link>
</div>
);
};
if (!session) {
return (
<div className="hero">
<div className="navbar">
{signOutButtonNode()}
{signInButtonNode()}
</div>
<div className="text">
You aren't authorized to view this page
</div>
</div>
)
}
return (
<div className="hero">
<Head>
<title>Index Page</title>
</Head>
<div className="navbar">
{signOutButtonNode()}
{signInButtonNode()}
</div>
<div className="text">
Hello world
</div>
</div>
);
};
export const getServerSideProps = async ({ req }) => {
const session = await getSession({ req });
return {
props: {
session,
},
};
};
export default IndexPage;
Now, if we visit http://localhost:3000/, we should be able to view the following screen:
We can log in using our Gmail account once we click on the Sign In button. Once we're signed in, we should be able to view the following screen on http://localhost:3000/:
All the details of the authenticated user are present in the session prop of the page:
We can show the details of the authenticated user by fetching the details from the session prop. Also, the authenticated user will now be visible in the Strapi administration panel:
Conclusion
In this tutorial, we learned how we can authenticate a Next.js application using Strapi and NextAuth. We've worked with the REST API that Strapi provides out of the box. However, a similar solution can also be implemented for using GraphQL.
The code for this tutorial is available on GitHub. I've also created a boilerplate for using Strapi with Next.js. It'll help you get up and running with Strapi and Next.js really quickly. Feel free to give it a try.
Get started with Strapi by creating a project using a starter or trying our live demo. Also, consult our forum if you have any questions. We will be there to help you.