How to use the @nuxtjs/strapi Module to add Authentication to a Nuxt Application
Tags: nuxtjs, javascript, tutorial, jamstack
Published: 2022-03-01 15:55:10

---

canonical_url: https://strapi.io/blog/how-to-use-the-nuxt-strapi-module-to-add-authentication-to-a-nuxt-application?utm_source=dev.to&utm_medium=post&utm_id=blog

---
Author: Alex Godwin

# How to use the @nuxtjs/strapi Module to add Authentication to a Nuxt Application
In this tutorial, we will learn about authentication (local authentication) in Strapi. We’ll create a simple blog app where authenticated users can create, read, and delete posts. In contrast, unauthenticated users can only view a list of posts but cannot read, create, or delete posts. We’ll have a login route, signup route, and a create post route where users can create posts from. We’ll also be working with Image uploads to see how users can upload images from the Nuxt.js frontend to our Strapi backend.


## What do you need for this tutorial?
- Basic Knowledge of [V](https://vue.js.org)[ue.j](https://vue.js.org)
- Knowledge of JavaScript, and
- [Node.js](https://nodejs.org) (v14 recommended for strapi).


## Table of Contents
- [Installing Strapi](http://strapi.io)
- Building the API with Strapi
- [Installing Nuxt.js](http://nuxtjs.org)
- [Installing](http://https://strapi.nuxt.js.org) [@nuxtjs/strapi](http://https://strapi.nuxt.js.org)
- Building the frontend with Nuxt.js

Here’s what we’ll be building:


![](https://paper-attachments.dropbox.com/s_06CB13E69812BFF1B9A02D2AD8E00870D4E689AA97E45BEBACAE215F4CD6279E_1644626730301_Screenshot+from+2022-02-12+01-42-06.png)

![](https://paper-attachments.dropbox.com/s_06CB13E69812BFF1B9A02D2AD8E00870D4E689AA97E45BEBACAE215F4CD6279E_1644626885276_Screenshot+from+2022-02-12+01-45-59.png)

![](https://paper-attachments.dropbox.com/s_06CB13E69812BFF1B9A02D2AD8E00870D4E689AA97E45BEBACAE215F4CD6279E_1644626951274_Screenshot+from+2022-02-12+01-48-23.png)

![](https://paper-attachments.dropbox.com/s_06CB13E69812BFF1B9A02D2AD8E00870D4E689AA97E45BEBACAE215F4CD6279E_1644627048959_Screenshot+from+2022-02-12+01-49-53.png)


Let’s get started!

## Installing Strapi

[T](https://docs.strapi.io/developer-docs/latest/getting-started/introduction.html)[he Strapi documentation](https://docs.strapi.io/developer-docs/latest/getting-started/introduction.html) [](https://docs.strapi.io/developer-docs/latest/getting-started/introduction.html)[says that Strapi is a flexible, open-source](https://docs.strapi.io/developer-docs/latest/getting-started/introduction.html)[,](https://docs.strapi.io/developer-docs/latest/getting-started/introduction.html) [](https://docs.strapi.io/developer-docs/latest/getting-started/introduction.html)[h](https://docs.strapi.io/developer-docs/latest/getting-started/introduction.html)[eadless CMS that gives developers the freedom to choose their favo](https://docs.strapi.io/developer-docs/latest/getting-started/introduction.html)[u](https://docs.strapi.io/developer-docs/latest/getting-started/introduction.html)[rite tools and frameworks](https://docs.strapi.io/developer-docs/latest/getting-started/introduction.html) [and allows](https://docs.strapi.io/developer-docs/latest/getting-started/introduction.html) [editors to](https://docs.strapi.io/developer-docs/latest/getting-started/introduction.html) [](https://docs.strapi.io/developer-docs/latest/getting-started/introduction.html)[manage and distribute their content](https://docs.strapi.io/developer-docs/latest/getting-started/introduction.html) [easily](https://docs.strapi.io/developer-docs/latest/getting-started/introduction.html)[.](https://docs.strapi.io/developer-docs/latest/getting-started/introduction.html) Strapi enables the world's largest companies to accelerate content delivery while building beautiful digital experiences by making the admin panel and API extensible through a plugin system.

Strapi helps us build an API quickly with no hassle of creating a server from scratch. With Strapi, we can do everything literally, and it’s easily customizable. We can add our code and edit functionalities easily. Strapi is amazing, and its capabilities would leave you stunned. 

Strapi provides an admin panel to edit and create APIs. It also provides easily-editable code and uses JavaScript.



![Strapi Admin Dashboard](https://paper-attachments.dropbox.com/s_06CB13E69812BFF1B9A02D2AD8E00870D4E689AA97E45BEBACAE215F4CD6279E_1644625383034_Screenshot+from+2022-01-22+14-52-01.png)

![Strapi code](https://paper-attachments.dropbox.com/s_06CB13E69812BFF1B9A02D2AD8E00870D4E689AA97E45BEBACAE215F4CD6279E_1644625421778_Screenshot+from+2022-01-22+14-52-53.png)


[To install Strapi, head over to the S](https://strapi.io/documentation/developer-docs/latest/installation/cli.html)[trapi](https://strapi.io/documentation/developer-docs/latest/installation/cli.html) [docs at Strapi](https://strapi.io/documentation/developer-docs/latest/installation/cli.html) and run the following commands:

```shell
    yarn create strapi-app my-project //using yarn
    npx create-strapi-app@latest my-project //using npx
```


    Replace `my-project` with the name you wish to call your application directory. Your package manager will create a directory with the specified name and install Strapi.

If you followed the instructions correctly, you should have Strapi installed on your machine. Run the following command:

```shell
    yarn develop //using yarn
    npm run develop //using npm
```

To start our development server, Strapi starts our app on http://localhost:1337/admin. 

# Building the API with Strapi

We have Strapi up and running; the next step is to create our products content-type.


1. To Create the Article Content Type
- Click on `content-type` builder in the side menu.
- Under `Collection-types`, click `create new collection type`.
- Add new content-type named article.
- Create fields under article content-type.
    - Name as short text
    - Description as short text
    - content as rich text
    - Image as a single type.
![Article Collection type](https://paper-attachments.dropbox.com/s_06CB13E69812BFF1B9A02D2AD8E00870D4E689AA97E45BEBACAE215F4CD6279E_1644625933018_Screenshot+from+2022-02-12+01-30-30.png)



2. Add User Relationship
- Create a relation field under article. 
- Select `User` (from users-permissions-user), and click on “user has many articles” relation.
- Save the article content type.
![Relationship between Users and articles](https://paper-attachments.dropbox.com/s_06CB13E69812BFF1B9A02D2AD8E00870D4E689AA97E45BEBACAE215F4CD6279E_1644626084942_Screenshot+from+2022-02-12+01-33-45.png)



3. Create User and Enable User Permission and Roles
- Strapi provides a Users collection type by default. Head to `settings` on the side menu, and select `Roles` under `Users and Permissions Plugin`.
- Click on `Authenticated` and check all permissions.
- Save your changes, then go back and click on `public`.
- Check only the `find` and `findOne` permissions.
- Click `save` to save changes.
- Create a user called `author`  with whatever credentials you’d like, but select the authenticated role and enable email confirmation.
- Create an article and select `Users_permissions_user` as author. This means that the user `author` created the article.
- Save the article and proceed.

Save the `content-types`. We can now view our API in JSON format when we visit [http://localhost:1337/api/articles](http://localhost:1337/api/articles).

Now that we’ve created our Strapi API, we need to build our frontend with Nuxt.js.


## Installing Nuxt.js

[To install Nuxt.js](https://nuxtjs.org/docs/2.x/get-started/installation)[,](https://nuxtjs.org/docs/2.x/get-started/installation) [visit the Nuxt docs.](https://nuxtjs.org/docs/2.x/get-started/installation)

We want to use Nuxt in SSR mode and server hosting; we also want Tailwind CSS as our preferred CSS framework. Select those and whatever options you want for the rest. Preferably, leave out C.I, commit-linting, and style-linting.


- To install Nuxt.js, run the following commands:

```shell
    yarn create nuxt-app <project-name> //using yarn
    npx create-nuxt-app <project-name> //using npx
    npm init nuxt-app <project-name> //using npm
```

It will ask you some questions (Name, Nuxt Options, UI Framework, TypeScript, Linter, Testing Framework, etc.).

Once all the questions are answered, the dependencies will be installed. The next step is to navigate to the project folder and launch it using the command below.

```shell
    yarn dev //using yarn
    npm run dev //using npm
```

We should have Nuxt running on [http://localhost:3000](http://localhost:3000).


## Installing @nuxtjs/strapi

We need to query our Strapi backend API, and Strapi provides a great package for that. We could use [Nuxt’s native @nuxtjs/http module](http://https://http.nuxtjs.org) or [axios](https://www.npmjs.com/package/axios) to query our API, but [@nuxtjs/strapi](https://strapi.nuxtjs.org) makes it easier. To install @nuxtjs/strapi:


- Run the command below:

```shell
    yarn add @nuxtjs/strapi@^0.3.4 //using yarn
    npm install @nuxtjs/strapi@^0.3.4 //using npm
```

- Open the `nuxt.config.js` file and add the following code to the file.

```js
    modules: [
      // ...other modules
      '@nuxtjs/strapi',
    ]
    
    strapi: {
      url: process.env.STRAPI_URL || `http:localhost:1337/api`,
      entities: ['articles'],
    }
```

We can now use @nuxtjs/strapi to make API calls and continue building our pages and components.

[The @nuxtjs/strapi documentation can be found](https://strapi.nuxtjs.org/) [here.](http://https://strapi.nuxtjs.org/)


- We’ll be using @nuxtjs/strapi in two ways: 


    this.$strapi() //from properties such as methods, data, computed
    
    $strapi() //from nuxtjs lifecycle methods


## Installing  [@nuxtjs/markdownit](https://www.npmjs.com/package/@nuxtjs/markdownit)

Strapi rich text  gives us the privilege of writing markdown in our content. In order to parse the markdown content from the backend, we need to [install the @nuxtjs/markdownit package](https://www.npmjs.com/package/@nuxtjs/markdownit). 


- Run the command below.

```shell
    yarn add @nuxtjs/markdownit //using yarn
    npm install @nuxtjs/markdownit //using npm
```


- Add the following lines of code to your nuxt.config.js file.

```js
    modules: [
     //...other modules
    '@nuxtjs/markdownit'
    ],
    
     markdownit: {
        preset: 'default',
        linkify: true,
        breaks: true,
        injected: true,
        // use: ['markdown-it-div', 'markdown-it-attrs'],
      },
```

Now, we can use @nuxtjs/markdownit to parse our markdown content. [The @nuxtjs/markdownit documentation can be found](https://www.npmjs.com/package/@nuxtjs/markdownit) [here.](http://https://www.npmjs.com/package/@nuxtjs/markdownit)


## Building the Frontend with NuxtJs

We can proceed with building the user-interface of our blog app.

**To Build the Signup Page:**

- Execute the following lines of code to create a `signup.vue` file in the pages directory.

```shell
    cd pages
    touch signup.vue
```

-  Fill signup.vue with the following lines of code.

 ```vue
     <template>
      <div class="w-4/5 mx-auto md:w-1/2 text-center my-12">
        <div v-show="error !== ''" class="p-3 border">
          <p>{{ error }}</p>
        </div>
        <h1 class="font-bold text-2xl md:text-4xl mt-5">Signup</h1>
        <form @submit="createUser">
          <div>
            <input
              v-model="email"
              class="p-3 my-5 border w-full"
              type="email"
              placeholder="email"
            />
          </div>
          <div>
            <input
              v-model="username"
              class="p-3 my-5 border w-full"
              type="text"
              placeholder="username"
            />
          </div>
          <div>
            <input
              v-model="password"
              class="p-3 my-5 border w-full"
              type="password"
              placeholder="password"
            />
          </div>
          <div>
            <button
              class="button--green"
              :disabled="email === '' || password === '' || username === ''"
              type="submit"
            >
              Signup
            </button>
          </div>
        </form>
      </div>
    </template>
    <script>
    export default {
      data() {
        return {
          email: '',
          username: '',
          password: '',
          error: '',
        }
      },
      methods: {
        async createUser(e) {
          e.preventDefault()
          try {
            const newUser = await this.$strapi.register({
              email: this.email,
              username: this.username,
              password: this.password,
            })
            console.log(newUser)
            if (newUser !== null) {
              this.error = ''
              this.$nuxt.$router.push('/articles')
            }
          } catch (error) {
            this.error = error.message
          }
        },
      },
      middleware: 'authenticated',
    }
    </script>
    <style></style>
```

We just built our signup logic; when users provide their email, username and password, and click the signup button, we invoke the `createUser` method. All we’re doing in this method is registering a new user using the `@nuxtjs/strapi` module i.e `this.$strapi.register()` method. Then, we redirect the user to the `/articles` route. If the email belongs to an existing user, an error message is displayed at the top of the page. Finally, we’re using `nuxtjs middleware` feature to invoke a custom-made `middleware` that we’re going to create.

**To Build the Login Page**

- Execute the following lines of code to create a `login.vue` file in the pages directory.

```vue
    touch login.vue
```

- Fill up login.vue with the following lines of code.

```vue
    <template>
      <div class="w-4/5 mx-auto md:w-1/2 text-center my-12">
        <div v-show="error !== ''" class="p-3 border">
          <p>{{ error }}</p>
        </div>
        <h1 class="font-bold text-2xl md:text-4xl mt-5">Login</h1>
        <form @submit="loginUser">
          <div>
            <input
              v-model="identifier"
              class="p-3 my-5 border w-full"
              type="email"
              placeholder="email"
            />
          </div>
          <div>
            <input
              v-model="password"
              class="p-3 my-5 border w-full"
              type="password"
              placeholder="password"
            />
          </div>
          <div>
            <button
              :disabled="identifier === '' || password === ''"
              class="button--green"
              type="submit"
            >
              Login
            </button>
          </div>
        </form>
      </div>
    </template>
    <script>
    export default {
      data() {
        return {
          identifier: '',
          password: '',
          error: '',
        }
      },
      methods: {
        async loginUser(e) {
          e.preventDefault()
          try {
            const user = await this.$strapi.login({
              identifier: this.identifier,
              password: this.password,
            })
            console.log(user)
            if (user !== null) {
              this.error = ''
              this.$nuxt.$router.push('/articles')
            }
          } catch (error) {
            this.error = 'Error in login credentials'
          }
        },
      },
      middleware: 'authenticated',
    }
    </script>
    <style></style>
```

We’ve just built our login logic; users provide a unique identifier (email) and password, then click on the login button, which calls the loginUser method. This method attempts to log the user in using the @nuxtjs/strapi module i.e this.$strapi.login() method and returns a user object if a user is found or an error if the credentials are invalid. The user is redirected to the `/article` route if the process was successful and an error message is displayed if an error occurred.

**To Create an Authenticated Middleware**

Let’s create our middleware function:


- Execute the following lines of code to create an authenticated.js file in the middleware directory.

```shell
    cd middleware
    touch authenticated.js
```

- Fill up authenticated.js with the following code.

```js
    export default function ({ $strapi, redirect }) {
      if ($strapi.user) {
        redirect('/articles')
      }
    }
```

What we have done is set up a middleware that checks if a user is logged in or not. If a user is logged in, we redirect them to the `/articles` page, this middleware is useful for preventing a logged in user from accessing the Login, Signup and ‘/’ route. We don’t want to have a logged in user signing up on our app for whatsoever reason.

**To Build the Nav Component**

- Execute the following lines of code to create a `Nav.vue` file in the components directory.

```shell
    cd components
    touch Nav.vue
```


- Fill up the file with the following code.

```js
    <template>
      <div
        class="flex space-x-5 items-center justify-center bg-black text-white py-3 sm:py-5"
      >
        <NuxtLink to="/articles">Articles</NuxtLink>
        <div v-if="$strapi.user === null">
          <NuxtLink class="border-r px-3" to="/login">Login</NuxtLink>
          <NuxtLink class="border-r px-3" to="/signup">Signup</NuxtLink>
        </div>
        <div v-if="$strapi.user !== null">
          <span class="border-r px-3">{{ $strapi.user.username }}</span>
          <NuxtLink class="border-r px-3" to="/new">Create Post</NuxtLink>
          <button class="pl-3" @click="logout">Logout</button>
        </div>
      </div>
    </template>
    <script>
    export default {
      name: 'Nav',
      methods: {
        async logout() {
          await this.$strapi.logout()
          this.$nuxt.$router.push('/')
        },
      },
    }
    </script>
    <style></style>
```

In the *Nav* component, all we’re doing is building a navigation bar for our application. Using the @nuxt/strapi module, we’re checking if there is no logged in user, then we display signup and login optiona in the nav bar. But if a user is logged in, we display their username, logout option and a “create post” link.

Note: 

```
    $strapi.user //returns the loggedin user or null
```

When a user clicks the logout button, we invoke a logout function, which in turn invokes the $`strapi.logout()` function that logs the user out. Then, we redirect the user to the `'``/``'` route using the `$nuxt.$router.push()` method.

**To Build the Homepage**


- Execute the following lines of code to create an `index.vue` file in the pages directory.

```shell
    cd pages
    code index.vue
```

- Fill up the index.vue file with the following code.

```js
    <template>
      <div class="container">
        <div>
          <h1 class="title">Welcome To The BlogApp</h1>
          <div class="links">
            <NuxtLink to="/login" class="button--green"> Login </NuxtLink>
            <NuxtLink to="/articles" class="button--grey"> Continue Free </NuxtLink>
          </div>
        </div>
      </div>
    </template>
    <script>
    export default {
      middleware: 'authenticated',
    }
    </script>
    <style>
    /* Sample `apply` at-rules with Tailwind CSS
    .container {
    @apply min-h-screen flex justify-center items-center text-center mx-auto;
    }
    */
    .container {
      margin: 0 auto;
      min-height: 100vh;
      display: flex;
      justify-content: center;
      align-items: center;
      text-align: center;
    }
    .title {
      font-family: 'Quicksand', 'Source Sans Pro', -apple-system, BlinkMacSystemFont,
        'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
      display: block;
      font-weight: 300;
      font-size: 80px;
      color: #35495e;
      letter-spacing: 1px;
    }
    .subtitle {
      font-weight: 300;
      font-size: 42px;
      color: #526488;
      word-spacing: 5px;
      padding-bottom: 15px;
    }
    .links {
      padding-top: 15px;
    }
    </style>
```

What we have here is our homepage. We’re using Nuxt.js middleware feature to invoke a custom-made middleware that we created.

**To Build the Articles Page**

- Execute the following lines of code to create a articles.vue file in the pages directory.

```shell
    cd pages
    touch articles.vue
```

- Fill it up with the following code.

```js
    <template>
      <div>
        <Nav class="mx-auto sticky top-0" />
        <h1 class="text-center my-5">All our articles</h1>
        <div
          v-show="error !== ''"
          class="sticky z-100 border p-5 m-3 top-0 bg-black text-white text-center mx-auto w-4/5 sm:w-4/5 md:w-4/5 lg:w-1/2"
        >
          <p class="m-1 sm:m-3">{{ error }}</p>
          <button class="button--grey" @click="resetError()">Ok</button>
        </div>
        <div
          v-for="(article, i) in data.data"
          :key="i"
          class="sm:flex sm:space-x-5 my-5 shadow-lg mx-auto w-4/5 sm:w-4/5 md:w-4/5 lg:w-1/2"
        >
          <img
            :src="`http://localhost:1337${article.attributes.Image.data.attributes.formats.small.url}`"
            class="max-h-screen sm:h-48"
          />
          <div class="px-2 sm:pr-2 sm:text-left text-center">
            <h3 class="font-bold my-3">{{ article.attributes.name }}</h3>
            <p class="my-3">{{ article.attributes.description }}</p>
            <button class="button--green mb-4 sm:mb-0" @click="readPost(article)">
              Read more
            </button>
          </div>
        </div>
      </div>
    </template>
    <script>
    export default {
      async asyncData({ $strapi, $md }) {
        const data = await $strapi.$articles.find({ populate: '*' })
        return { data }
      },
      data() {
        return {
          error: '',
        }
      },
      methods: {
        readPost(article) {
          if (this.$strapi.user) {
            this.error = ''
            this.$nuxt.$router.push(`/article/${article.id}`)
          } else {
            this.error = 'Please Login to read articles'
          }
        },
        resetError() {
          this.error = ''
        },
      },
    }
    </script>
    <style></style>
```

First, we’ll use the @nuxtjs/strapi module to find all our articles. Then, we’ll display the articles on our page. In the `readPost` method, we’re checking if a user is logged in before allowing the user to read a post. If the user is not logged in, we display an error message saying “Please, log in to read articles.”

**To Build the Article Content Page**


- Execute the following lines of code to create a _id.vue file in the pages directory.

```shell
    mkdir article
    touch _id.vue
```

- Fill the _id.vue file with the following code.

```js
    <template>
      <div>
        <Nav class="mx-auto sticky top-0" />
        <div class="w-4/5 sm:w-1/2 mx-auto my-5">
          <h3 class="my-5 font-bold text-4xl">
            {{ article.name }}
          </h3>
          <img
            :src="`http://localhost:1337${article.Image.url}`"
            class="max-h-screen"
          />
          <p class="mt-5 font-bold">
            written by {{ article.users_permissions_user.username }}
          </p>
          <div class="my-5" v-html="$md.render(article.content)"></div>
          <button
            v-if="
              $strapi.user && article.users_permissions_user.id === $strapi.user.id
            "
            class="button--grey"
            @click="deletePost(article.id)"
          >
            Delete
          </button>
        </div>
      </div>
    </template>
    <script>
    export default {
      async asyncData({ $strapi, route }) {
        const id = route.params.id
        const article = await $strapi.$articles.findOne(id, {
          populate: '*',
        })
        return { article }
      },
      methods: {
        async deletePost(id) {
          await this.$strapi.$articles.delete(id)
          this.$nuxt.$router.push('/articles')
        },
      },
      middleware({ $strapi, redirect }) {
        if ($strapi.user === null) {
          redirect('/articles')
        }
      },
    }
    </script>
    <style scoped>
    h1 {
      font-weight: 700;
      font-size: 2rem;
      margin: 0.5em 0;
    }
    </style>
```

On this page, we’re displaying an individual article with its complete content using markdownit i.e `$md.render(article.content)` , author name, and more. We’ll also display a delete button if the current user is the author of the post; we’ll check for that by using the `@nuxtjs/strapi` module. We don’t want an unauthorized user to delete a post they didn’t create. Finally, in the middleware, we’re checking for a logged in user; if there’s none, we’ll redirect to the ‘/articles’ route, making sure the article content page is totally inaccessible to unauthenticated users.

**NOTE:** 

The `Users_permissions` plugin is currently broken, but we can populate the `users_permissions_user` field manually from the Strapi backend. Follow the steps below to do so:

- Navigate to the `src/api/controllers` folder.
- Click on the `article.js` file.
- Fill it up with the following code.

```js
    'use strict';
    /**
     *  article controller
     */
    const { createCoreController } = require('@strapi/strapi').factories;
    
    
    module.exports = createCoreController('api::article.article', ({ strapi }) => ({
        async findOne(ctx) {
            console.log(ctx.request.params.id)
            const data = await strapi.service('api::article.article').findOne(ctx.request.params.id, {
                populate: ['Image', 'users_permissions_user']
            })
            delete data.users_permissions_user.password
            return data
        }
    }));
``` 

What have manually populated the `Image` and `users_permission_user` fields. Then, we’ll delete the password so that it is not passed along in the response to the client.

**To Build the Create Article Page**


- Execute the following lines of code to create a `New.vue` file in the pages directory.

```shell
    touch New.vue
```

- Fill up the New.vue file with the following lines of code 

```js
    <template>
      <div class="w-4/5 mx-auto md:w-1/2 text-center my-12 overflow-hidden">
        <form ref="form" @submit="createPost">
          <h2 class="font-bold text-2xl md:text-4xl mt-5">Create a new post</h2>
          <div>
            <input
              v-model="form.name"
              name="Title"
              type="text"
              placeholder="title"
              class="p-3 my-3 border w-full"
            />
          </div>
          <div>
            <input
              v-model="form.description"
              name="description"
              type="text"
              placeholder="description"
              class="p-3 my-3 border w-full"
            />
          </div>
          <div>
            <textarea
              v-model="form.content"
              name="Content"
              cols="30"
              rows="10"
              class="p-3 my-3 border w-full"
            ></textarea>
          </div>
          <div>
            <input
              type="file"
              name="Image"
              class="p-3 my-3 border w-full"
              @change="assignFileInput()"
            />
          </div>
          <div>
            <button
              class="button--green"
              :disabled="
                form.name === '' ||
                form.description === '' ||
                form.content === '' ||
                fileInput === ''
              "
              type="submit"
            >
              Create
            </button>
          </div>
        </form>
      </div>
    </template>
    <script>
    export default {
      data() {
        return {
          form: {
            name: '',
            description: '',
            content: '',
            users_permissions_user: this.$strapi.user.id,
          },
          fileInput: '',
        }
      },
      methods: {
        async createPost(e) {
          const formData = new FormData()
          let file
          const formElements = this.$refs.form.elements
          formElements.forEach((el, i) => {
            if (el.type === 'file') {
              file = el.files[0]
            }
          })
          formData.append(`files.Image`, file, file.name)
          formData.append('data', JSON.stringify(this.form))
          e.preventDefault()
          await this.$strapi.$articles.create(formData)
          this.$nuxt.$router.push('/articles')
        },
        assignFileInput() {
          const formElements = this.$refs.form.elements
          formElements.forEach((el, i) => {
            if (el.type === 'file') {
              this.fileInput = el.files[0] !== undefined ? el.files[0].name : ''
            }
          })
        },
      },
      middleware({ $strapi, redirect }) {
        if (!$strapi.user) {
          redirect('/articles')
        }
      },
    }
    </script>
    <style></style>
```

We just created the logic to enable authenticated users to create new articles. The logic is complicated, especially the *file upload* logic, so let’s work through it step by step.

We built a content creation form as usual, with fields for title, description, image upload and content, and the create button. 


1. Using the v-model directive, we linked up the fields with their respective data property; file inputs do not support the v-model directive, so we’ve built a workaround. 
2. What we’ve done is create an assignInput()` method that is invoked when the field input with file type changes.
3. When a change occurs, we check if the type of the form element that changed is a file. If it is, we assign the name of the selected file as the value of `fileInput`. 

Next, the `createPost()` method allows users create articles. 

1. Using `FormData` we append the form object from the page’s data property in string form to `FormData` with a data property. 
2. We do the same thing for file input but we append it to FormData with a `files.image` property. This is because, for multipart data, Strapi requires that the property be preceded by files i.e `files.${fieldname}`  and our fieldname from the article content-type is image.

With all that done, we should have our create article logic working fine.

[The frontend repo for this tutorial can be found here](https://github.com/oviecodes/nuxt-strapi-auth)
[The backend repo for this tutorial can be found here](https://github.com/oviecodes/strapi-auth/tree/strapi-v4)[.](https://github.com/oviecodes/strapi-auth/tree/strapi-v4)
[](https://github.com/oviecodes/strapi-auth/tree/strapi-v4)
We’ve come to the end of this tutorial. By now, you have what it takes to tackle Strapi authentication with NuxtJs in your arsenal.