javascript3 Min Read

Authenticating Strapi backend with Next.js and next-auth using credentials and jwt

Gorav Singal

April 18, 2021

TL;DR

Authenticate users from Next.js to Strapi using next-auth's CredentialsProvider with email/password, then store and use the JWT token for subsequent authenticated REST API calls.

Authenticating Strapi backend with Next.js and next-auth using credentials and jwt

Introduction

Strapi is a backend system provides basic crud operations with customizable content types, and auto-magically provide its Rest APIs. Next.js is an excellent framework over React.js which uses capability of React.js and provides SEO benefits by rendering pages at server side.

In this post, I will authenticate a registered user fron next.js to strapi and use its Rest API with jwt for further authenticated operations.

What We Will Learn

  • Render a pre-built login form, and its corresponding actions
  • authentication will be with strapi email/password system.
  • Signout functionality
  • Save jwt in session
  • Use jwt tokens in rest-apis for authenticated calls

Pre-requisites

  1. Have a registered and active user in strapi.
  2. Have a content type.
  3. This content type is only usable by authenticated users.

NPM Libraries required

  • axios
  • next
  • next-auth
  • react
  • react-dom

Using Next-auth

Create a file named /pages/api/auth/[...nextauth].js

import NextAuth from 'next-auth'
import Providers from 'next-auth/providers'
import axios from 'axios'

const options = {
  providers: [
    Providers.Credentials({
      name: 'Credentials',
      credentials: {
        email: { label: "Email", type: "text", placeholder: "[email protected]" },
        password: {  label: "Password", type: "password" }
      },
    async authorize(credentials) {
        try {
          const { data } = await axios.post(`${process.env.NEXT_PUBLIC_API_URL}/auth/local`, {
            identifier: credentials.email,
            password: credentials.password
          });
          if (data) {
            return data;
          }
          else {
            return null;
          }
        } catch (e) {
          // console.log('caught error');
          // const errorMessage = e.response.data.message
          // Redirecting to the login page with error message          in the URL
          // throw new Error(errorMessage + '&email=' + credentials.email)
          return null;
        }
      }
    })
  ],

  session: {
    jwt: true,
  },

  callbacks: {
    // Getting the JWT token from API response
    jwt: async (token, user, account) => {
      const isSignIn = user ? true : false;
      if (isSignIn) {
        token.jwt = user.jwt;
        token.id = user.user.id;
        token.name = user.user.username;
        token.email = user.user.email;
      }
      return Promise.resolve(token);
    },
  
    session: async (session, user) => {
      session.jwt = user.jwt;
      session.id = user.id;
      return Promise.resolve(session);
    },
  }
}

export default (req, res) => NextAuth(req, res, options)

Edit _app.js

import { Provider } from 'next-auth/client'

function MyApp({ Component, pageProps }) {
  return (
    <Provider session={pageProps.session}>
        <Component {...pageProps} />
    </Provider>
  );
}

export default MyApp

.env.local Environment variable file

NEXTAUTH_URL=http://localhost:3000
NEXT_PUBLIC_API_URL=http://localhost:1337

Summary so far

We have configured our Next.js frontend so that we will be able to:

  • Configured a credential provider in next-auth with strapi backend.
  • Configured action to be performed when user submit Login form.
  • Authentication rest call to strapi backend and upon successful authentication, save jwt token to session
  • Easily identify if a user has logged-in or not.
  • Easily get jwt token, if user has authenticated.

Playground with Sign-in/Sign-out and Authenticated Rest call

import Head from 'next/head'
import { signIn, signOut, useSession, getSession } from 'next-auth/client'
import axios from 'axios'

export default function Home(initialData) {
  const [ session, loading ] = useSession()
  return (
    <div className='container'>
      <Head>
        <title>Create Next App</title>
        <link rel="icon" href="/favicon.ico" />
        <link rel="stylesheet" href="/style.css"/>
      </Head>

      <h1>Auth Test</h1>

      <div>
          {!session && <>
          Not signed in <br/>
          <button onClick={() => signIn()}>Sign in</button>
        </>}
        {session && <>
          Signed in as {session.user.email} <br/>
          <button onClick={() => signOut()}>Sign out</button>
        </>}
      </div>

      <h1>Content...</h1>

      <div>
        {initialData.journals && initialData.journals.map((each, index) => {
          return(
            <div key={index}>
              <h3>{each.Title}</h3>
              <p>{each.Journal}</p>
            </div>
          )
        })}
      </div>
      
    </div>
  )
}

export async function getServerSideProps({req}) {
  let headers = {}
  const session = await getSession({ req });
  if (session) {
    headers = {Authorization: `Bearer ${session.jwt}`};
  }
  let journals = [];
  try {
    let {data } = await axios.get(`${process.env.NEXT_PUBLIC_API_URL}/journals`, {
      headers: headers,
    })
    journals = data;
  } catch (e) {
    console.log('caught error');
    journals = [];
  }
  
  return {props: {journals: journals}}  
}

Understanding getServerSideProps

First we are checking, if a session is there. If it is, then we are fetching jwt token from session and using it to pass in a Rest call for getting a content type.

Detect User is Logged-in or not

const [ session, loading ] = useSession()

{!session && <>
          Not signed in <br/>
          <button onClick={() => signIn()}>Sign in</button>
        </>}

Also see How to use Next-auth in Client side vs Server Side

The magic methods of next-auth gives you methods to get session information. You just need to check, if session is present.

If there is no session, it gives you a signin action and when you click on this button, you will be presented with the ready-made form.

Share

Related Posts

Nextjs - Fixing Loading External Images and Issue of Url Paramater Not Allowed

Nextjs - Fixing Loading External Images and Issue of Url Paramater Not Allowed

Introduction In this post, we will see How to load external images to your next…

Request Entity Too Large(413) - Uploading File with Formdata with Axios and Custom header

Request Entity Too Large(413) - Uploading File with Formdata with Axios and Custom header

Introduction I was trying to upload images to my backend using rest APIs. I was…

Nextjs - How to Build Next.js Application on Docker and Pass API Url

Nextjs - How to Build Next.js Application on Docker and Pass API Url

Introduction In this post we will see: How to prepare a docker image for your…

Nextjs - How to Redirect to Another Page and Pass State

Nextjs - How to Redirect to Another Page and Pass State

Introduction We have a page, for example a . And, upon submission we would want…

How to use Draft.js WYSWYG with Next.js and Strapi Backend, Edit/Update Saved Article

How to use Draft.js WYSWYG with Next.js and Strapi Backend, Edit/Update Saved Article

Introduction This post is in contuation of our previous post: How to use Draft…

How to use Draft.js WYSWYG with Next.js and Strapi Backend, Create and View Article with Image Upload

How to use Draft.js WYSWYG with Next.js and Strapi Backend, Create and View Article with Image Upload

Introduction In this post, we will use in Next.js with strapi. And, we will…

Latest Posts

AI Video Generation in 2025 — Models, Costs, and How to Build a Cost-Effective Pipeline

AI Video Generation in 2025 — Models, Costs, and How to Build a Cost-Effective Pipeline

AI video generation went from “cool demo” to “usable in production” in 2024-202…

AI Models in 2025 — Cost, Capabilities, and Which One to Use

AI Models in 2025 — Cost, Capabilities, and Which One to Use

Choosing the right AI model is one of the most impactful decisions you’ll make…

AI Image Generation in 2025 — Models, Costs, and How to Optimize Spend

AI Image Generation in 2025 — Models, Costs, and How to Optimize Spend

Generating one image with AI costs between $0.002 and $0.12. That might sound…

AI Coding Assistants in 2025 — Every Tool Compared, and Which One to Actually Use

AI Coding Assistants in 2025 — Every Tool Compared, and Which One to Actually Use

Two years ago, AI coding meant one thing: GitHub Copilot autocompleting your…

AI Agents Demystified — It's Just Automation With a Better Brain

AI Agents Demystified — It's Just Automation With a Better Brain

Let’s cut through the noise. If you read Twitter or LinkedIn, you’d think “AI…

Supply Chain Security — Protecting Your Software Pipeline

Supply Chain Security — Protecting Your Software Pipeline

In 2024, a single malicious contributor nearly compromised every Linux system on…