Implementing Authenticated API Requests to Strapi
Tags: api, strapi, authentication, nextjs
Published: 2022-01-06 15:31:09

[Strapi](https://strapi.io/) 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](https://nextjs.org/). 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](https://nextjs.org/) 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](https://nodejs.org/en/), 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:

```bash

$ mkdir authenticated_requests && cd authenticated_requests

```

Inside that folder, install `Strapi`:

```bash

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

```

Note that this is very similar to using `create-react-app` if you have worked with [React](https://reactjs.org/) before. The name of the Strapi application is called `backend` since 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/](http://localhost:1337/).

![Strapi registration page](https://imgur.com/pqACfXX.png)

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

```bash

$ 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 Dashboard](https://imgur.com/6fbBlzS.png)

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.

![Strapi Create a new CollectionType](https://i.imgur.com/zb5X8Wu.png)

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:

![Strapi Create an Entry](https://imgur.com/iilCVgv.png)

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:

```bash

$ 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:

```bash

$ cd frontend

$ npm run dev

```

Then, navigate to [http://localhost:3000/](http://localhost:3000/) and you should see this:

![Next.js home page](https://imgur.com/Ar30tii.png)

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

```js

export default function Home() {

    return (

        &lt;div>

            &lt;h1>Implementing Authenticated API Requests to Strapi&lt;/h1>

        &lt;/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:

```js

export default function Home({ posts }) {

    console.log(posts);

    return (

        &lt;div>

            &lt;h1>Implementing Authenticated API Requests to Strapi&lt;/h1>

        &lt;/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/](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.

![Next.js Status Code 403](https://i.imgur.com/TXd855H.png)

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](https://nextjs.org/docs/basic-features/environment-variables).

### 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**.

![Strapi dashboard create a new user 1](https://imgur.com/IPuIAdh.png)

![Strapi dashboard create a new user 2](https://imgur.com/Kn9qDLQ.png)

### Step 2: Setting Roles

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

![Strapi dashboard set user roles 1](https://imgur.com/uk1nHwJ.png)

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.

![Strapi dashboard set user roles 2](https://imgur.com/i43ZPWa.png)

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:

```js

export default function Home({ posts, loginResponseData }) {

    console.log(posts);

    console.log(loginResponseData);

    return (

        &lt;div>

          &lt;h1>Implementing Authenticated API Requests to Strapi&lt;/h1>

          {posts && posts.map((_post_) => (

            &lt;div _key_={post.id}>

              &lt;h3>{post.attributes.title}&lt;/h3>

            &lt;/div>

          ))}

      &lt;/div>

    );

}

export async function getServerSideProps(ctx) {

    const loginData = {

        identifier: '&lt;User Email>',

        password: '&lt;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 = posts.data

    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 `&lt;User Email>` and `&lt;User Password>` with the email and password of the user you created.

![Next.js JWT response](https://i.imgur.com/XFwKja3.png)

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:

```js

...

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](https://github.com/maticzav/nookies) to implement this functionality.

Inside the `frontend` folder, install Nookies:

```bash

$ npm install nookies

```

Next, update the `pages/index.js` file:

```js

import { parseCookies, setCookie }  from 'nookies'

export default function Home({posts}) {

  return (

    &lt;div>

          &lt;h1>Implementing Authenticated API Requests to Strapi&lt;/h1>

          {posts && posts.map((_post_) => (

            &lt;div _key_={post.id}>

              &lt;h3>{post.attributes.title}&lt;/h3>

            &lt;/div>

          ))}

      &lt;/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 = posts.data

  return {

    props: {  

      posts:posts      

    }

  }

}

 // if there isn’t a jwt token authenticate the user 

  

    const loginData = {

       identifier: '&lt;User Email>',

       password: '&lt;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 = posts.data

  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 `Application` tab using the development tools in your browser.

![Next.js JWT cookies](https://imgur.com/9FcWxTU.png)

## Conclusion

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.