Cannot Read Property 'headers' of Undefined Nuxt

Introduction

In this tutorial, you'll implement hallmark in a Nuxt.js app using the Auth module.

For the purpose of this tutorial, you'll be using JWT for authentication.

Beneath is a quick demo of what you'll be edifice in this tutorial:

Animated gif of the app showing a user signing in

You can find the source code for this application at GitHub.

Warning: Several of the packages in this tutorial now comprise dependencies with known vulnerabilities. In a production setting, you would resolve these issues by upgrading these packages, finding alternatives, or creating forked versions with patched fixes. However, within the express context of a tutorial, it provides educational value as-is.

Prerequisites

To complete this tutorial, you will demand:

  • Node.js installed locally, which you can do past following How to Install Node.js and Create a Local Evolution Environment.
  • A valid Git installation is optionally required for cloning the API, consult Getting Started with Git.

Some familiarity with Vue.js and Nuxt.js may be benign. You can refer to this mail if you're getting started with Nuxt.js.

This tutorial was verified with Node v13.thirteen.0, npm v6.xiv.4, vue v2.half dozen.11, and nuxt v2.12.2.

Step one — Spinning upwardly a Sample API

You are free to use whatever framework that works best for you. Notwithstanding, for quick development, this tutorial will clone an API built with AdonisJs.

The API utilizes:

  • JWT (JSON Web Tokens) for hallmark
  • SQLite
  • CORS enabled

The API has three endpoints:

  • /annals: endpoint for user registration
  • /login: endpoint for authenticating users
  • /me: endpoint for getting details for the currently authenticated user and information technology is protected by an auth middleware, which means a user must be authenticated to access the endpoint

First, run the following command in your terminal window:

                      
  1. git clone https://github.com/do-community/jwt-auth-api.git

Then, navigate to the projection directory:

                      
  1. cd jwt-auth-api

And install the API dependencies:

                      
  1. npm install

Annotation: When running install, you may encounter issues with sqlite3 version 4.0.one depending on the version of Node you are running. Refer to the changelog to decide compatibility with your environment.

At the fourth dimension of original publication, the latest version of Node was 10. I option is to downgrade your version of Node to x.20.1 (with the agreement that it is nearing terminate-of-life support). And so, run npm install.

A second option is to remove the package-lock.json file which volition cause the organization to look for 4.2.0 which is supported upwardly to Node 13. You may need to besides downgrade your version of Node to thirteen.13.0. Then, run npm install.

A third option would be to modify parcel.json to a version of sqlite3 supported by your current version of Node, remove package-lock.json, and run npm install. However, at the fourth dimension of testing, v.0.0 is not yet released to handle Node 14+ support.

Other symptoms of incompatibility include the post-obit errors: TypeError: Cannot read property 'information' of undefined and Error: Cannot find module '[...]/node_modules/sqlite3/lib/bounden/[...]/node_sqlite3.node'.

Next, rename .env.example to .env:

                      
  1. mv .env.case .env

And generate an APP_KEY:

                      
  1. npx @adonisjs/cli@4.0.12 key:generate

You should see:

                      
  1. Output

    generated: unique APP_KEY

Once that'southward coomplete, allow'south run the migrations:

                      
  1. npx @adonisjs/cli@4.0.12 migration:run

Now, you can outset the API:

                      
  1. # ensure that you are in the `jwt-auth-api` project directory
  2. npm start

Y'all tin can access the API on http://127.0.0.ane:3333/api. Go out this running in a terminal window for the residual of the duration of the tutorial.

Step two — Creating a Nuxt.js App

Now, y'all can create a Nuxt.js app. Open up a new terminal window and utilize vue-cli to initialize a new Vue project with the Nuxt starter template:

                      
  1. npx vue-cli@ii.9.6 init nuxt/starter nuxt-auth

Note: At the fourth dimension of testing, vue-cli is deprecated. @vue/cli is the current command line tool for Vue projects. And @vue/cli-init is the recommended arroyo for legacy vue-cli projects. Yet, create-nuxt-app is the recommended approach for modern Nuxt projects.

Adjacent, you demand to navigate to the project directory:

                      
  1. cd nuxt-auth

And install the dependencies:

          npm install                  

And then, you lot tin launch the app:

                      
  1. npm run dev

The app should be running on http://localhost:3000. Y'all can view the application in a web browser to see the default Vue application created by vue-cli.

Step 3 — Installing Necessary Nuxt.js Modules

At present, let'south install the Nuxt.js modules that you'll be needing for your app. Yous'll be using the Nuxt Auth module and the Nuxt Axios module, since the auth module makes use of Axios internally:

                      
  1. # ensure that you are in the `nuxt-auth` projection directory
  2. npm install @nuxtjs/auth@iv.5.1 @nuxtjs/axios@five.3.one --save

Once that'due south completed, open nuxt.config.js:

                      
  1. nano nuxt.config.js

Add the code beneath to nuxt.config.js:

nuxt.config.js

          module.exports            =            {            // ...                          modules              :              [                                      '@nuxtjs/axios'              ,                                      '@nuxtjs/auth'                                      ]              ,                        }                  

Side by side, y'all need to set up the modules. Paste the code below into nuxt.config.js:

nuxt.config.js

          module.exports            =            {            // ...                          axios              :              {                                      baseURL              :              'http://127.0.0.1:3333/api'                                      }              ,                                      auth              :              {                                      strategies              :              {                                      local              :              {                                      endpoints              :              {                                      login              :              {              url              :              'login'              ,              method              :              'post'              ,              propertyName              :              'information.token'              }              ,                                      user              :              {              url              :              'me'              ,              method              :              'get'              ,              propertyName              :              'data'              }              ,                                      logout              :              false                                      }                                      }                                      }                                      }                        }                  

Here, yous set the base URL that Axios will utilise when making requests. In our example, we are referencing the sample API we set up before.

And then, you lot define the authentication endpoints for the local strategy corresponding to those on your API:

  • On successful authentication, the token will be bachelor in the response as a token object within a data object.
  • Similarly, the response from the /me endpoint will be inside a information object.
  • Lastly, yous set logout to faux since your API doesn't have an endpoint for logout. Y'all'll simply remove the token from localStorage when a user logs out.

Step 4 — Creating a Navbar Component

To style your app, you lot can make use of Bulma.

Open nuxt.config.js and paste the code beneath within the link object that is inside the caput object:

nuxt.config.js

          module.exports            =            {            // ...            head            :            {            // ...            link            [            // ...                          {                                      rel              :              'stylesheet'              ,                                      href              :              'https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.1/css/bulma.min.css'                                      }                        ]            }            ,            // ...            }                  

At present, let'southward create the Navbar component:

                      
  1. nano components/Navbar.vue

And add together the following code:

components/Navbar.vue

                      <template>            <nav            class            =            "navbar is-light"            >            <div            class            =            "container"            >            <div            grade            =            "navbar-make"            >            <nuxt-link            form            =            "navbar-item"            to=            "/"            >Nuxt Auth<            /nuxt-link>            <button            course            =            "button navbar-burger"            >            <bridge>            <            /bridge>            <span>            <            /span>            <span>            <            /span>            <            /push button>            <            /div>            <div            class            =            "navbar-bill of fare"            >            <div            course            =            "navbar-finish"            >            <div            class            =            "navbar-particular has-dropdown is-hoverable"            >            <a            class            =            "navbar-link"            >            My Business relationship            <            /a>            <div            class            =            "navbar-dropdown"            >            <nuxt-link            form            =            "navbar-particular"            to=            "/profile"            >My Profile<            /nuxt-link>            <60 minutes            class            =            "navbar-divider"            /            >            <a            class            =            "navbar-particular"            >Logout<            /a>            <            /div>            <            /div>            <template>            <nuxt-link            class            =            "navbar-item"            to=            "/register"            >Annals<            /nuxt-link>            <nuxt-link            class            =            "navbar-particular"            to=            "/login"            >Log In<            /nuxt-link>            <            /template>            <            /div>            <            /div>            <            /div>            <            /nav>            <            /template>                  

The Navbar component contains links to login, register, profile, and logout.

Next, let's update the default layout to make use of the Navbar component.

Open default.vue:

                      
  1. nano layouts/default.vue

And supplant the content with the following:

layouts/default.vue

                      <template>            <div>            <Navbar/            >            <nuxt/            >            <            /div>            <            /template>            <script>            import            Navbar            from            '~/components/Navbar'            export            default            {            components            :            {            Navbar            }            }            <            /script>                  

Too, let'southward update the homepage.

Open index.vue:

                      
  1. nano pages/alphabetize.vue

And supercede the content with the following:

pages/index.vue

                      <template>            <department            form            =            "section"            >            <div            form            =            "container"            >            <h1            grade            =            "title"            >Nuxt Auth<            /h1>            <            /div>            <            /section>            <            /template>                  

At this point, you should take an application that displays a title of "Nuxt Auth" with a header bar with navigation links:

App page with title and header bar

Stride v — Treatment User Registration

Inside the pages directory, create a new register.vue file:

                      
  1. nano pages/register.vue

And add the following lawmaking:

pages/annals.vue

                      <template>            <section            grade            =            "department"            >            <div            grade            =            "container"            >            <div            class            =            "columns"            >            <div            grade            =            "column is-4 is-offset-4"            >            <h2            class            =            "title has-text-centered"            >Register!            <            /h2>            <Notification            :bulletin=            "error"            v-            if            =            "fault"            /            >            <form method=            "post"            @submit.forestall=            "register"            >            <div            form            =            "field"            >            <label            course            =            "label"            >Username<            /label>            <div            grade            =            "control"            >            <input                   type=            "text"            class            =            "input"            proper noun=            "username"            v-model=            "username"            required            /            >            <            /div>            <            /div>            <div            class            =            "field"            >            <label            grade            =            "label"            >Email<            /label>            <div            class            =            "control"            >            <input                   type=            "email"            class            =            "input"            name=            "email"            v-model=            "email"            required            /            >            <            /div>            <            /div>            <div            class            =            "field"            >            <label            class            =            "label"            >Password<            /label>            <div            class            =            "command"            >            <input                   type=            "countersign"            course            =            "input"            proper name=            "password"            v-model=            "password"            required            /            >            <            /div>            <            /div>            <div            class            =            "command"            >            <button type=            "submit"            class            =            "button is-nighttime is-fullwidth"            >Register<            /push>            <            /div>            <            /form>            <div            class            =            "has-text-centered"            manner=            "margin-tiptop: 20px"            >            Already got an account?            <nuxt-link to=            "/login"            >Login<            /nuxt-link>            <            /div>            <            /div>            <            /div>            <            /div>            <            /section>            <            /template>            <script>            import            Notification            from            '~/components/Notification'            export            default            {            components            :            {            Notification,            }            ,            data            (            )            {            return            {            username            :            ''            ,            electronic mail            :            ''            ,            password            :            ''            ,            error            :            null            }            }            ,            methods            :            {            async            register            (            )            {            endeavour            {            look            this            .$axios.            postal service            (            'register'            ,            {            username            :            this            .username,            electronic mail            :            this            .email,            password            :            this            .password            }            )            expect            this            .$auth.            loginWith            (            'local'            ,            {            data            :            {            electronic mail            :            this            .email,            password            :            this            .password            }            ,            }            )            this            .$router.            push            (            '/'            )            }            catch            (e)            {            this            .error            =            due east.response.data.bulletin            }            }            }            }            <            /script>                  

This contains a grade with three fields: username, e-mail, and countersign. Each field is bound to respective information on the component. When the class is submitted, a register method will be called. Using the Axios module, you make a postal service request to the /register endpoint, passing forth the user data. If the registration was successful, you lot make use of the Auth module'south loginWith(), using the local strategy and passing the user data to log the user in. Then, yous redirect the user to the homepage. If in that location is an error during the registration, you set the error data as the error message gotten from the API response.

If there is an error, the error message is displayed by a Notification component.

Create a new Notification.vue file inside components:

                      
  1. nano components/Notifaction.vue

And paste the lawmaking below in information technology:

components/Notification.vue

                      <template>            <div            class            =            "notification is-danger"            >            {            {            message            }            }            <            /div>            <            /template>            <script>            consign            default            {            name            :            'Notification'            ,            props            :            [            'bulletin'            ]            }            <            /script>                  

The Notification component accepts a bulletin props, which is the fault message.

Now, you can exam out user registration:

Register page with Username, Email, and Password fields

Register page but with a notification message to the user that there was an error

Step 6 — Handling LoggedUsers Logged In and Logged Out

Upon successful registration, users should be logged in but there is currently no way for the app to know whether users are logged in or not. And so permit's fix that past updating the Navbar component and adding some computed backdrop.

Earlier you do just that, allow's first actuate the Vuex store by creating an index.js file inside the store directory. The Auth module stores user hallmark condition too as user details inside Vuex country in an auth object. So you can check if a user is logged in or not with this.$store.state.auth.loggedIn, which will either return truthful or false. Similarly, you tin get a user'south details with this.$store.state.auth.user, which will be null if no user is logged in.

Note: You can too access the user authentication condition as well every bit the user details direct with the Auth module using this.$auth.loggedIn and this.$auth.user respectively.

Since you might want to use the computed properties in multiple places in your app, permit'due south create store getters.

Open index.js:

                      
  1. nano shop/index.js

And paste the code below in it:

store/index.js

                      export            const            getters            =            {            isAuthenticated            (            state            )            {            return            country.auth.loggedIn            }            ,            loggedInUser            (            country            )            {            return            state.auth.user            }            }                  

Here, you create two getters. The first one (isAuthenticated) will render the authentication status of a user and the second (loggedInUser) will render the details or the logged in user.

Next, let's update the Navbar component to brand utilise of the getters. Replace the content of components/Navbar.vue with the following:

components/Navbar.vue

                      <template>            <nav            grade            =            "navbar is-low-cal"            >            <div            form            =            "container"            >            <div            form            =            "navbar-make"            >            <nuxt-link            form            =            "navbar-item"            to=            "/"            >Nuxt Auth<            /nuxt-link>            <button            class            =            "button navbar-burger"            >            <bridge>            <            /span>            <span>            <            /span>            <span>            <            /span>            <            /button>            <            /div>            <div            class            =            "navbar-menu"            >            <div            grade            =            "navbar-end"            >            <div            class            =            "navbar-detail has-dropdown is-hoverable"            v-              if              =              "isAuthenticated"                        >            <a            class            =            "navbar-link"            >                          {              {              loggedInUser.username              }              }                        <            /a>            <div            form            =            "navbar-dropdown"            >            <nuxt-link            class            =            "navbar-item"            to=            "/profile"            >My Profile<            /nuxt-link>            <hour            class            =            "navbar-divider"            /            >            <a            class            =            "navbar-item"            >Logout<            /a>            <            /div>            <            /div>            <template            v-              else                        >            <nuxt-link            class            =            "navbar-item"            to=            "/annals"            >Register<            /nuxt-link>            <nuxt-link            class            =            "navbar-detail"            to=            "/login"            >Log In<            /nuxt-link>            <            /template>            <            /div>            <            /div>            <            /div>            <            /nav>            <            /template>                          <script>                                      import              {              mapGetters              }              from              'vuex'                                      export              default              {                                      computed              :              {                                      ...              mapGetters              (              [              'isAuthenticated'              ,              'loggedInUser'              ]              )                                      }                                      }                                      <              /script>                              

You lot create the computed properties past using the spread operator (...) to extract the getters from mapGetters. Then using isAuthenticated, you display the user carte du jour or links to login or register depending on whether the user is logged in or not. Likewise, yous utilise loggedInUser to display the authenticated user username.

Now, if you give your app a refresh, yous should see something similar to below:

App page with the user's username in the header

Footstep 7 — Handling User Log In

Now, let'southward permit returning users the ability to log in.

Create a new login.vue file inside the pages directory:

          nano pages/login.vue                  

And paste the code beneath in it:

pages/login.vue

                      <template>            <section            form            =            "department"            >            <div            class            =            "container"            >            <div            class            =            "columns"            >            <div            class            =            "column is-4 is-kickoff-4"            >            <h2            course            =            "title has-text-centered"            >Welcome back!            <            /h2>            <Notification            :message=            "mistake"            v-            if            =            "error"            /            >            <form method=            "postal service"            @submit.forbid=            "login"            >            <div            class            =            "field"            >            <label            class            =            "label"            >Email<            /label>            <div            class            =            "control"            >            <input                   type=            "e-mail"            class            =            "input"            proper name=            "email"            5-model=            "electronic mail"            /            >            <            /div>            <            /div>            <div            class            =            "field"            >            <label            grade            =            "label"            >Password<            /label>            <div            class            =            "control"            >            <input                   blazon=            "password"            form            =            "input"            name=            "password"            v-model=            "password"            /            >            <            /div>            <            /div>            <div            class            =            "control"            >            <push button type=            "submit"            grade            =            "push is-nighttime is-fullwidth"            >Log In<            /button>            <            /div>            <            /grade>            <div            class            =            "has-text-centered"            style=            "margin-height: 20px"            >            <p>            Don't take an account?            <nuxt-link to=            "/register"            >Register<            /nuxt-link>            <            /p>            <            /div>            <            /div>            <            /div>            <            /div>            <            /section>            <            /template>            <script>            import            Notification            from            '~/components/Notification'            consign            default            {            components            :            {            Notification,            }            ,            data            (            )            {            render            {            email            :            ''            ,            countersign            :            ''            ,            error            :            aught            }            }            ,            methods            :            {            async            login            (            )            {            endeavour            {            await            this            .$auth.            loginWith            (            'local'            ,            {            information            :            {            e-mail            :            this            .e-mail,            countersign            :            this            .password            }            }            )            this            .$router.            push            (            '/'            )            }            catch            (e)            {            this            .mistake            =            e.response.data.message            }            }            }            }            <            /script>                  

This is quite similar to the annals page. The form contains two fields: email and password. When the course is submitted, a login method will exist chosen. Using the Auth module loginWith() and passing along the user information, you log the user in. If the authentication was successful, you redirect the user to the homepage. Otherwise, set error to the error message gotten from the API response. Again, you are using the Notification component from earlier on to display the error message.

App Welcome Back page containing two fields: email and password

Step 8 — Displaying the User Profile

Let'due south allow logged in users to view their profile.

Create a new profile.vue file inside the pages directory:

                      
  1. nano pages/profile.vue

And paste the code below in information technology:

pages/profile.vue

                      <template>            <section            class            =            "department"            >            <div            form            =            "container"            >            <h2            class            =            "title"            >My Profile<            /h2>            <div            course            =            "content"            >            <p>            <strong>Username:            <            /potent>            {            {            loggedInUser.username            }            }            <            /p>            <p>            <strong>E-mail:            <            /strong>            {            {            loggedInUser.email            }            }            <            /p>            <            /div>            <            /div>            <            /section>            <            /template>            <script>            import            {            mapGetters            }            from            'vuex'            export            default            {            computed            :            {            ...            mapGetters            (            [            'loggedInUser'            ]            )            }            }            <            /script>                  

Notice how you lot are using the loggedInUser getter from before on to display the user details.

Clicking on the My Contour link should issue in a My Profile folio being displayed.

My Profile page displaying username and email

Step 9 — Logging Users Out

Update the logout link inside the Navbar component.

Open Navbar.vue:

                      
  1. nano components/Navbar.vue

Alter the logout link to use @click="logout":

components/Navbar.vue

                      // ...            <div            class            =            "navbar-dropdown"            >            <nuxt-link            class            =            "navbar-particular"            to=            "/profile"            >My Profile<            /nuxt-link>            <hr            class            =            "navbar-divider"            /            >            <a            class            =            "navbar-item"            @click=              "logout"                        >Logout<            /a>            <            /div>            // ...                  

When the logout link is clicked, it volition trigger a logout method.

Side by side, allow'south add the logout method inside the script department of the Navbar component:

components/Navbar.vue

                      // ...            export            default            {            // ...            methods            :            {                          async              logout              (              )              {                                      wait              this              .$auth.              logout              (              )              ;                                      }              ,                        }            ,            }                  

You lot phone call the logout() of the Auth module. This will delete the user's token from localstorage and redirect the user to the homepage.

Step 10 — Restricting the Profile Page

As information technology stands at present, anybody can visit the profile page. And if the user is not logged in, it volition consequence in an error.

TypeError on app page

To prepare this, you need to restrict the profile folio to only logged in users. Luckily for u.s., you tin can achieve that with the Auth module. The Auth module comes with an auth middleware, which you tin utilise in this scenario.

So let'south add the auth middleware to the profile page. Update the script section as below:

pages/contour.vue

                      // ...            export            default            {                          middleware              :              'auth'              ,                        // ...            }                  

Now when a user that is not logged in tries to visit the profile page, the user will exist redirected to the login page.

Step 11 — Creating a Guest Middleware

Again as information technology stands, even as a logged in user, you can still access the login and annals pages. One way to prepare that is to restrict login and register pages to only users that are non logged in. Yous can do that past creating a guest middleware.

Inside the middleware directory, create a new guest.js file:

                      
  1. nano middleware/guest.js

And paste the code beneath in it:

middleware/invitee.js

                      export            default            function            (                          {              store,              redirect              }                        )            {            if            (store.state.auth.loggedIn)            {            return            redirect            (            '/'            )            }            }                  

A middleware accepts the context as its kickoff argument. And so y'all extract store and redirect from the context. Then, yous check if the user is logged in then redirect the user to the homepage. Otherwise, you lot allow the normal execution of the request.

Adjacent, permit'due south make utilize of this middleware. Update the script department of both login and register as below:

pages/login.vue and pages/annals.vue

                      // ...            consign            default            {                          middleware              :              'guest'              ,                        // ...            }                  

Now, everything will be working equally expected.

Determination

In this tutorial, you looked at how to implement hallmark in a Nuxt.js application using the Auth module. Yous besides saw how to continue the authentication flow sleek by making use of middleware.

To larn more near the Auth module, cheque out the docs.

If you lot'd like to learn more than near Vue.js, check out our Vue.js topic page for exercises and programming projects.

mcdowellseestrocces.blogspot.com

Source: https://www.digitalocean.com/community/tutorials/implementing-authentication-in-nuxtjs-app

0 Response to "Cannot Read Property 'headers' of Undefined Nuxt"

Postar um comentário

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel