Implementing Authenticated API Requests to Strapi

Strapi is an awesome technology that can be included as part of a tech stack for creating full-fledged applications. It is known as a headless CMS because it serves only as the backend infrastructure for your application. Therefore, it can handle the entire backend for your application, leaving you with the flexibility to choose whatever frontend technology you’d like to use for your application.

Since Strapi only takes care of the backend part of your application, data stored in the database using Strapi are turned into an API — either REST or GraphQL — that can then be consumed by the frontend part of your application. This frontend could be built by any technology of your choice, though this guide will make use of Next.js. In most cases, you wouldn’t want just any user accessing your application to be able to interact with your entire backend infrastructure and modify data in your database. In other words, there should be a way to make sure that only authenticated users can access and interact with Strapi.

Why Authenticate Requests?

Authenticating requests is important for any application because not every endpoint provided by your Strapi backend should be publicly available to be consumed by any frontend client. This is especially true for requests that modify part of the database. For example, a POST or DELETE request should be somehow protected from public modification and only allow users with the right credentials and permission access.

In this tutorial, you’ll be guided through how to implement authenticating requests in Strapi using Next.js as the example frontend to ensure users are properly authenticated before allowing them access to Strapi.

Tutorial Requirements

Since you’ll be using Next.js to build up the frontend for this tutorial, a basic knowledge of Next.js fundamentals is required. In addition, make sure you have the latest version of Node.js installed, preferably version 12 or 14, as other versions might not be supported by Strapi. Also, it would be helpful to have a basic knowledge of how Strapi works, although this is not strictly required for this guide’s purposes.

Setting up Strapi

Let’s start by creating a new Strapi application. In your terminal, open a new folder:

$ mkdir authenticated_requests && cd authenticated_requests

Inside that folder, install Strapi:

$ npx create-strapi-app@latest backend --quickstart

Note that this is very similar to using create-react-app if you have worked with React before. The name of the Strapi application is called backendsince Strapi predominantly handles the backend. You also added the --quickstart flag here, which helps to quickly bootstrap a new Strapi app using Sqlite-3, permitting a simplified means of configuring the database. Once done, Strapi should be automatically launched in a new window in your default browser, and you should see a screen similar to the screenshot below. By default, Strapi runs on http://localhost:1337/.

However, to launch the server manually, use this command:

$ cd backend$ npm run develop

Next, fill in the needed credentials to successfully log in to the Strapi admin panel. Once you’re logged in, you should see this screen:

Strapi is well known for having a very clean admin area, with very streamlined functionality for you to get started quickly. Note that Strapi automatically creates a User collection type, which you will come back to later on. Collection types allow you to create a new model in your database with the required fields and data types to hold the actual data. This is created using the Content-Type builder library.

Create a new collection type of your own by clicking on the Create new collection type button and give it a display name of Post. It is recommended to keep the display name singular, as Strapi will by default pluralize the display name. Next, click on the Continue button, and add a new field with a text field type. Give it a name title and click on the Finish button. Finally, click Save to successfully add this new collection type. After clicking on the Save button, the server needs to restart for changes to be reflected.

Before you proceed, add at least one title to the Posts collection. The Posts collection you just created earlier can be seen under the Content Manager page. Make sure you publish each new entry after saving them, by clicking on the publish button:

For the most part, you wouldn’t be touching the actual Strapi code. Instead, you would be modifying content using the admin panel. Now, you’ve successfully set up the Strapi backend; in the next section, you’ll be setting up the Next.js frontend.

Setting up Next.js

Before we dive into making authenticated requests, you’ll first need to bootstrap your Next.js frontend. Inside the authenticated_requests folder, run the following command to create a new Next.js application:

$ npx create-next-app@latest frontend --use-npm

Here, you gave the application the name frontend since this would be where the frontend code will reside. You also added the --use-npm flag, to strictly use npm to install Next.js, though yarn could also be used.

Once you have Next.js installed, change the directory to the frontend folder and then run the development server like so:

$ cd frontend$ npm run dev

Then, navigate to http://localhost:3000/ and you should see this:

Next, open up the frontend folder using a text editor and replace the content inside the pages/index.js file with the following code:

export default function Home() {    return (        <div>            <h1>Implementing Authenticated API Requests to Strapi</h1>        </div>    );}

The server will automatically reload and reflect the changes. Now you’ve successfully bootstrapped a new Next.js project. In the next section, you’ll be implementing authenticated requests.

Implementing Authenticated Requests

In your Next.js application, update the pages/index.js file like so:

export default function Home({ posts }) {    console.log(posts);    return (        <div>            <h1>Implementing Authenticated API Requests to Strapi</h1>        </div>    );}export async function getServerSideProps(ctx) {    // get posts from strapi REST API    const res = await fetch('http://localhost:1337/api/posts');    let posts = await res.json();    return {        props: {            posts: posts,        },    };}

Here, you’re fetching all the posts and loading each post object in your console. Note that if you navigate back to http://localhost:3000/ after saving the file, you will see a status code of 403 in your console. This status stands for Forbidden, because by default, Strapi prevents the public from accessing data from your Strapi backend.

If you’d like, you can change the default setting and allow all public access. However, for this guide, you will only allow authenticated users access, using the steps outlined below.

Note that for a production environment you wouldn’t want to expose your URL like this http://localhost:3000/. Instead, you can store them inside an environmental variable.

Step 1: Create a New User

Remember that Strapi automatically creates a User collection type. Therefore, create a new user by clicking on the Add new entry button on the Users page. Make sure you set the Confirmed button to On for that user, as well as the Role to Authenticated.

Step 2: Setting Roles

Now, on the Settings page, access the Users & Permissions Plugin and click on Roles.

Here, you will see two roles, Authenticated and Public. Click on Authenticated, and you will be taken to a new screen where you can set the actions of what authenticated users can perform on the Posts collection type. For this example, click on Select all in the Permissions section.

This setting will allow any authenticated user access to see and modify content in the Strapi backend. Note that you can also customize this to the way you see fit by selecting the exact role you want the authenticated user to have. For example, you might not want to allow the authenticated user to be able to delete content, so you could disable this.

Whichever set of permissions you decide on, be sure to Save your changes.

Step 3: Sending Authenticated Request

Next, you will send an authenticated request in Next.js to Strapi to authenticate the user you just created.

Inside the pages/index.js file, update it with the following code:

export default function Home({ posts, loginResponseData }) {    console.log(posts);    console.log(loginResponseData);    return (        <div>          <h1>Implementing Authenticated API Requests to Strapi</h1>          {posts && => (            <div _key_={}>              <h3>{post.attributes.title}</h3>            </div>          ))}      </div>    );}export async function getServerSideProps(ctx) {    const loginData = {        identifier: '<User Email>',        password: '<User Password>',    };    const login = await fetch(`http://localhost:1337/api/auth/local`, {        method: 'POST',        headers: {            Accept: 'application/json',            'Content-Type': 'application/json',        },        body: JSON.stringify(loginData),    });    const loginResponseData = await login.json();    // get posts from strapi REST API    const res = await fetch(`http://localhost:1337/api/posts`);    let posts = await res.json();    posts =    return {        props: {            posts: posts,            loginResponseData: loginResponseData,        },    };}

Here, you’re making a POST request on server reload, passing on the details of the user you created (email and password), and logging the JSON response to the console. Save this file and refresh your browser.

Don’t forget to replace <User Email> and <User Password> with the email and password of the user you created.

Here, you will get back a JSON Web Token (JWT) attached to the user, and by using this JWT you can have access to the authenticated routes.

Update the res constant in the pages/index.js file by adding the JWT to the GET requests like so:

...const res = await fetch(`http://localhost:1337/api/posts`, {    headers: {      Authorization: `Bearer ${loginResponseData.jwt}`    }  });...

This will successfully return all the posts stored in the Strapi backend.

Step 4: Storing JWT with Nookies

Additionally, you can take this a step further and store the JWT inside of a cookie. With this, instead of authenticating users on each request made on every Next.js page, you can first check if this JWT cookie is present. If it is not present, then you can proceed to authenticate the user. This is quite similar when building a login functionality. You will be using a third-party package called Nookies to implement this functionality.

Inside the frontend folder, install Nookies:

$ npm install nookies

Next, update the pages/index.js file:

import { parseCookies, setCookie }  from 'nookies'export default function Home({posts}) {  return (    <div>          <h1>Implementing Authenticated API Requests to Strapi</h1>          {posts && => (            <div _key_={}>              <h3>{post.attributes.title}</h3>            </div>          ))}      </div>  )}export async function getServerSideProps(ctx) {  const jwt = parseCookies(ctx).jwt  // if there is a jwt token don’t authenticate the user again  if (jwt) {    // get posts from strapi REST API  const res = await fetch(`http://localhost:1337/api/posts`, {    headers: {      Authorization: `Bearer ${jwt}`    }  });  let posts = await res.json();  posts =  return {    props: {        posts:posts          }  }} // if there isn’t a jwt token authenticate the user     const loginData = {       identifier: '<User Email>',       password: '<User Password>',    }    const login = await fetch(`http://localhost:1337/api/auth/local`, {      method: "POST",      headers: {        'Accept': 'application/json',        'Content-Type': 'application/json'      },      body: JSON.stringify(loginData)    })    const loginResponseData = await login.json();    setCookie(ctx, 'jwt', loginResponseData.jwt, {      maxAge: 30 * 24 * 60 * 60,      path: '/',    })  // get posts from strapi REST API  const res = await fetch(`http://localhost:1337/api/posts`, {    headers: {      Authorization: `Bearer ${loginResponseData.jwt}`    }  });  let posts = await res.json();  posts =  return {    props: {        posts:posts          }  }}

Here, you’re setting a cookie called jwt using the setCookie method. Therefore, when the page initially loads, the cookie will be set, and you can then have access to this cookie using the parseCookies method in every other Next.js page you build. You can see the cookie under the Applicationtab using the development tools in your browser.


In this guide, you were introduced to the Strapi backend and how to use Next.js to interact with it. You learned how to create a new user and how to set roles and permissions in Strapi to restrict public access to the backend. Finally, you saw how to make authenticated requests in Next.js and store a cookie to make future authenticated requests easier.

If you want to continue learning more about this, a good challenge could be to build up a full login and logout functionality in Strapi using the Next.js frontend and make a protected route that only allows users that have logged in to have access to the page. In addition, this page should now allow authenticated users to make authenticated requests of some sort to your Strapi backend.




The open source Headless CMS Front-End Developers love.

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

Vuetiful Tabs (Part I)

Web Development Tutorial — Simple Draggable Table

CSS Tutorial: Learn the basics of CSS in 5 minutes

Creating Reusable Snackbars with Vuetify and Vuex

Go to the profile of Cory Reid

Demystifying the Event Loop (featuring setTimeout)

React, Reselect and Redux

Why Should You Have a Design System for Your Product?

design system represented

Importing External Style Sheets into the Angular Build

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store


The open source Headless CMS Front-End Developers love.

More from Medium

How to make RESTlet calls to Netsuite from NestJs?

CI/CD using GitHub Actions, Build/Push Docker Image to Docker Hub

Run Node.js from Google Sheets

How to create a model and do the migration in Node.js with Sequelize.js?