Nuxt.js Laravel Authentication: Everything You Need to Know

Nuxt.js is a free and open-source web application framework based on Vue.js, Node.js, Webpack, and Babel.js. Nuxt is inspired by Next.js, a framework of similar purpose based on React.js.

Nuxt is based on a robust modular architecture. With Nuxt.js, your application will be optimized out of the box.

Let’s use Nuxt.js and Laravel together to create an authentication system.

Nuxt js Laravel Authentication

We create an API that authenticates the user sent from the client. In return, we send a JSON Web Token. After signing in, we will send a JWT token to verify that the user is valid and needs to assign the proper resources he has requested. We use the Tymon laravel package to generate the token on the server side.

We start our project by installing two projects.

  1. Laravel
  2. Nuxt.js

Here are the steps to implement Nuxt.js Authentication with Laravel.

Step 1: Install Laravel and Nuxt.js.

Install Laravel using the following command. I have used Laravel Valet.

laravel new laravel-server

To install Nuxt.js, we need to install the community starter template. You can find it more in this URL: https://github.com/nuxt-community/starter-template.

Go to your terminal and install the nuxt.js starter template using the following command. But before that, we must install @vue/cli-init globally using the following command. Then we install the nuxt template.

yarn global add @vue/cli-init

Install the starter template.

vue init nuxt-community/starter-template nuxt-client

Nuxt js Laravel Authentication Tutorial With Example

Go into the nuxt-client project and install the dependencies using the following command.

npm install

We can start the development server of Nuxt.js using the following command.

npm run dev

Switch to the browser and access this URL: http://localhost:3000/. For example, you can see something like this below.

Nuxt js Laravel Authentication

Step 2: Configure Laravel.

Go to the Laravel project and open your favorite editor. Mine is VSCode.

Configure the database inside the .env file.

Migrate the database table using the following command.

php artisan migrate

We use Laravel as an API, so our project does not need web routes. Simply client makes a particular request, and the laravel server returns a JSON response. That is it. Nothing is more complicated.

So, we do not need any of the controller files that reside in the app >> Http >> Controller >> Auth folder. So remove it and create a new controller by the following command.

php artisan make:controller Auth\\AuthController

So it will create an AuthController.php file inside Controller’s Auth folder.

We write all the Register, Login, and Logout functions inside this AuthController file.

Also, remove routes >> web.php file and welcome.blade.php view file because we have our client.

All our api routes will go on inside routes >> api.php file.

Step 3: Install tymondesigns/jwt-auth package.

Inside the Laravel project root, type the following command. First, we need to install version 1 of the package.

composer require tymon/jwt-auth

After it finishes installing, go to the composer.json file and change the package version.

"require": {
        "php": "^7.1.3",
        "fideloper/proxy": "^4.0",
        "laravel/framework": "5.6.*",
        "laravel/tinker": "^1.0",
        "tymon/jwt-auth": "1.0.0-rc.2"
    },

Type the following command to update the package.

composer update

It will update the package.

Configure the Tymon package.

Go to the User.php model, which needs to implement the JWTSubject interface.

The interface comes with two methods that need to be implemented by the User model.

Write the following code inside the User.php file. We have just added two new functions and implemented an interface.

<?php

// User.php

namespace App;

use Tymon\JWTAuth\Contracts\JWTSubject;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable implements JWTSubject
{
    use Notifiable;

    protected $fillable = [
        'name', 'email', 'password',
    ];

    protected $hidden = [
        'password', 'remember_token',
    ];

    public function getJWTIdentifier()
    {
        return $this->getKey();
    }

    public function getJWTCustomClaims()
    {
        return [];
    }
}

Publish the package using the following command.

php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"

It will copy the file to this path: /config/jwt.php

Generate the jwt secret using the following command.

php artisan jwt:secret

Go to the config >> auth.php file and set the guard to api because we use Laravel as an API.

// auth.php

'defaults' => [
   'guard' => 'api',
    'passwords' => 'users',
 ],

'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],

        'api' => [
            'driver' => 'jwt',
            'provider' => 'users',
        ],
    ],

We have changed the default guard to API, and api uses the jwt driver instead of the token. Save the file, and you are good to go.

Step 4: Create Registration Functionality.

We created the AuthController.php file. So, write the first route inside routes >> api.php file. Then, remove existing code in an api.php file.

<?php

// api.php

Route::post('register', 'Auth\AuthController@register')->name('register');

Write the code inside the AuthController.php file to register a user.

<?php

// AuthController.php

namespace App\Http\Controllers\Auth;

use App\User;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;

class AuthController extends Controller
{
    public function register(Request $request)
    {
        $this->validate($request, [
            'name' => 'required',
            'email' => 'required|unique:users,email|email',
            'password' => 'required'
        ]);

        $user = User::create([
            'name' => $request->name,
            'email' => $request->email,
            'password' => bcrypt($request->password)
        ]);
  
        return $user;
    }
}

So, the request will be verified again with the server-side validation and then create a User in the database and return that user.

Now, we use API Resources to return JSON data in the standard format. So let us create a User Resource using the following command.

php artisan make:resource UserResource

It will create a folder inside app >> Http called Resources; inside that, it will create a file called UserResource.php.

We must modify the UserResource.php file and edit the function toArray(). We need to return an array containing only properties the client needs to display at the front end. So let us do that.

<?php

// UserResource.php

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\JsonResource;

class UserResource extends JsonResource
{
    /**
     * Transform the resource into an array.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return array
     */
    public function toArray($request)
    {
        return [
            'id' => $this->id,
            'name' => $this->name,
            'email' => $this->email
        ];
    }
}

Import the UserResource.php file inside the AuthController.php file.

<?php

// AuthController.php

namespace App\Http\Controllers\Auth;

use App\User;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Http\Resources\UserResource;

class AuthController extends Controller
{
    public function register(Request $request)
    {
        $this->validate($request, [
            'name' => 'required',
            'email' => 'required|unique:users,email|email',
            'password' => 'required'
        ]);

        $user = User::create([
            'name' => $request->name,
            'email' => $request->email,
            'password' => bcrypt($request->password)
        ]);

        return new UserResource($user);
    }
}

After registering a user, it will send the following formatted JSON response. We can test the request in Postman.

Laravel API Authentication

We can see that the user is created. The next step is to sign in to that user in our application, generate the JWT Token, and send that token to the client. So we send the User object and the token to the Nuxt.js client.

// RegisterController.php

public function register(Request $request)
{
        $this->validate($request, [
            'name' => 'required',
            'email' => 'required|unique:users,email|email',
            'password' => 'required'
        ]);

        $user = User::create([
            'name' => $request->name,
            'email' => $request->email,
            'password' => bcrypt($request->password)
        ]);

        if(!$token = auth()->attempt($request->only(['email', 'password'])))
        {
            return abort(401);
        }

        return (new UserResource($user))
            ->additional([
               'meta' => [
                 'token' => $token
             ]
        ]);
}

Here, we have checked the authentication against the newly created user. If the user is valid, it will generate a JWT token and send it back to the client. Then, we can test in the Postman by sending another request to the server.

Laravel JWT Authentication Example

 

Step 5: Create Login Functionality.

Registration is done. Now, go to the routes >> api.php file and add one route for login.

<?php

// api.php

Route::post('register', 'Auth\AuthController@register')->name('register');
Route::post('login', 'Auth\AuthController@login')->name('login');

Create a login() function inside AuthController and add the following code to sign in the user and generate the token.

// AuthController.php

public function login(Request $request)
{
        $this->validate($request, [
            'email' => 'required',
            'password' => 'required'
        ]);

        if(!$token = auth()->attempt($request->only(['email', 'password'])))
        {
            return response()->json([
                'errors' => [
                    'email' => ['There is something wrong! We could not verify details']
            ]], 422);
        }

        return (new UserResource($request->user()))
                ->additional([
                    'meta' => [
                        'token' => $token
                    ]
                ]);
}

If the requested user is valid, it will send a token to the client.

Also, we need to define another endpoint for our api. This api endpoint is for retrieving the currently signed-in user.

// api.php

Route::get('/user', 'Auth\AuthController@user');

Write the user() function inside the AuthController.php file.

// AuthController.php

public function user(Request $request)
{
     return new UserResource($request->user());
}

Step 6: Install the CORS module.

When we submit the request from the client-side, we get an error inside the browser called cross-site request origin. We get this error because our Nuxt.js application runs on PORT: 3000, and the Laravel server runs on a different port. So we need to resolve this error by installing a laravel-cors module.

Install the CORS module in the Laravel project by the following command.

composer require barryvdh/laravel-cors

Inside the app >> Http >> Kernel.php file, add the CORS middleware in the api guard.

// Kernel.php

'api' => [
    'throttle:60,1',
     'bindings',
     \Barryvdh\Cors\HandleCors::class,
],

Publish the Cors package using the following command.

php artisan vendor:publish --provider="Barryvdh\Cors\ServiceProvider"

That is it. Now, we can send a network request from the nuxt-client to the laravel-server.

Step 7: Install Bootstrap 4 inside a Nuxt project.

Install Bootstrap 4 using the following command.

yarn add bootstrap

# or

npm install bootstrap --save

Inside the root folder of nuxt-client, there is one file called nuxt.config.js.

We need to add the following lines of code inside that file.

// nuxt.config.js

css: ['./node_modules/bootstrap/dist/css/bootstrap.css'],
plugins: ['~plugins/bootstrap.js']

We need to include jquery. So write the following code to include jQuery.

// nuxt.config.js

const webpack = require('webpack');

build: {
    vendor: ['jquery', 'bootstrap'],
    plugins: [
      new webpack.ProvidePlugin({
        $: 'jquery',
        jQuery: 'jquery',
        'window.jQuery': 'jquery'
      })
    ],
    extend (config, { isDev, isClient }) {
      if (isDev && isClient) {
        config.module.rules.push({
          enforce: 'pre',
          test: /\.(js|vue)$/,
          loader: 'eslint-loader',
          exclude: /(node_modules)/
        })
      }
    }
  },

Our nuxt.config.js file looks like below.

// nuxt.config.js

const webpack = require('webpack')

module.exports = {
  head: {
    title: 'nuxt-client',
    meta: [
      { charset: 'utf-8' },
      { name: 'viewport', content: 'width=device-width, initial-scale=1' },
      { hid: 'description', name: 'description', content: 'Nuxt.js project' }
    ],
    link: [
      { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }
    ]
  },

  loading: { color: '#3B8070' },

  build: {
    vendor: ['jquery', 'bootstrap'],
    plugins: [
      new webpack.ProvidePlugin({
        $: 'jquery',
        jQuery: 'jquery',
        'window.jQuery': 'jquery'
      })
    ],
    extend (config, { isDev, isClient }) {
      if (isDev && isClient) {
        config.module.rules.push({
          enforce: 'pre',
          test: /\.(js|vue)$/,
          loader: 'eslint-loader',
          exclude: /(node_modules)/
        })
      }
    }
  },
  css: ['./node_modules/bootstrap/dist/css/bootstrap.css'],
  plugins: ['~plugins/bootstrap.js']
}

Inside the plugins folder, we need to create one file called bootstrap.js and write the following code inside it.

// bootstrap.js

if (process.BROWSER_BUILD) {
    require('bootstrap')
}

Save the file and go to the pages >> index.vue file and edit with the following code. Remove all other code.

// index.vue

<template>
  <div class="container">
    Page
  </div>
</template>

<script>

export default {
  
}
</script>

Go to the browser, and you can see that, Bootstrap 4 is successfully integrated.

Step 8: Create a Layout inside a Nuxt project.

Inside the layouts folder, create one more folder called partials; inside, create one Vue component called Navbar.js. Then, write the following code inside the Navbar.js file.

// Navbar.js

<template>
    <nav class="navbar navbar-expand-sm bg-light">
        <div class="container">
            <a class="navbar-brand" href="">
                Nuxt Laravel Auth
            </a>
            <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false">
                <span class="navbar-toggler-icon"></span>
            </button>

            <div class="collapse navbar-collapse" id="navbarSupportedContent">
                <!-- Right Side Of Navbar -->
                <ul class="navbar-nav ml-auto">
                    <!-- Authentication Links -->
                        <li class="nav-item">
                            <a class="nav-link" href="">Login</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link" href="">Register</a>
                        </li>
                        <li class="nav-item dropdown">
                            <a id="navbarDropdown" class="nav-link dropdown-toggle" href="#" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" v-pre>
                                Krunal <span class="caret"></span>
                            </a>

                            <div class="dropdown-menu dropdown-menu-right" aria-labelledby="navbarDropdown">
                                <a class="dropdown-item" href="">
                                    Logout
                                </a>  
                            </div>
                        </li>
                </ul>
            </div>
        </div>
    </nav>
</template>
<script>
export default {
    
}
</script>

Import this component inside layouts >> default.vue file.

// default.vue

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

Save the file and go to the browser. Our navbar has items like register, login, logout, and username. Of course, the navbar items will be changed in the future based on logged-in and out.

Step 9: Setup Nuxt Authentication.

We need to install the following two modules.

  1. @nuxjs/axios
  2. @nuxtjs/auth
yarn add @nuxtjs/axios @nuxtjs/auth

# or

npm install @nuxtjs/axios @nuxtjs/auth --save

Register these modules inside the nuxt.config.js file.

// nuxtjs.config.js

loading: { color: '#3B8070' },

modules: ['@nuxtjs/auth', '@nuxtjs/axios'],

Configure both of these modules individually inside a nuxt.config.js file.

// nuxt.config.js

axios: {
    baseURL: 'http://laravel-server.test/api'
  },
  auth: {
    strategies: {
      local: {
        endpoints: {
          login: { url: 'login', method: 'post', propertyName: 'meta.token' },
          user: { url: 'user', method: 'get', propertyName: 'data' },
          logout: {}
        }
      }
    }
  },

We defined the baseURL for a laravel-server API and the Auth endpoint. I am writing the whole nuxt.config.js file.

// nuxt.config.js

const webpack = require('webpack')

module.exports = {
  head: {
    title: 'nuxt-client',
    meta: [
      { charset: 'utf-8' },
      { name: 'viewport', content: 'width=device-width, initial-scale=1' },
      { hid: 'description', name: 'description', content: 'Nuxt.js project' }
    ],
    link: [
      { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }
    ]
  },

  loading: { color: '#3B8070' },

  modules: ['@nuxtjs/auth', '@nuxtjs/axios'],
  
  axios: {
    baseURL: 'http://laravel-server.test/api'
  },
  auth: {
    strategies: {
      local: {
        endpoints: {
          login: { url: 'login', method: 'post', propertyName: 'meta.token' },
          user: { url: 'user', method: 'get', propertyName: 'data' },
          logout: {}
        }
      }
    }
  },
  build: {
    vendor: ['jquery', 'bootstrap'],
    plugins: [
      new webpack.ProvidePlugin({
        $: 'jquery',
        jQuery: 'jquery',
        'window.jQuery': 'jquery'
      })
    ],
    extend (config, { isDev, isClient }) {
      if (isDev && isClient) {
        config.module.rules.push({
          enforce: 'pre',
          test: /\.(js|vue)$/,
          loader: 'eslint-loader',
          exclude: /(node_modules)/
        })
      }
    }
  },
  css: ['./node_modules/bootstrap/dist/css/bootstrap.css'],
  plugins: ['~plugins/bootstrap.js']
}

Step 10: Create a login.vue form.

Create a page called login.vue inside the pages directory. Then, write the following code inside it.

// login.vue

<template>
    <div class="container top">
        <div class="row justify-content-center">
            <div class="col-md-8">
                <div class="card">
                    <div class="card-header">Login</div>
                    <div class="card-body">
                        <form action="#">
                            <div class="form-group row">
                                <label for="email" class="col-sm-4 col-form-label text-md-right">Email</label>

                                <div class="col-md-6">
                                    <input type="email" class="form-control" required autofocus>
                                        <span class="invalid-feedback" role="alert">
                                            <strong></strong>
                                        </span>
                                </div>
                            </div>

                            <div class="form-group row">
                                <label for="password" class="col-md-4 col-form-label text-md-right">Password</label>

                                <div class="col-md-6">
                                    <input type="password" class="form-control" required>
                                        <span class="invalid-feedback" role="alert">
                                            <strong></strong>
                                        </span>
                                </div>
                            </div>

                            <div class="form-group row mb-0">
                                <div class="col-md-8 offset-md-4">
                                    <button type="submit" class="btn btn-primary">
                                        Login
                                    </button>
                                </div>
                            </div>
                        </form>
                    </div>
                </div>
            </div>
        </div>
    </div>
</template>

<script>
export default {
    
}
</script>

<style>
.top {
    margin-top: 80px;
}
</style>

Go to the layouts >> partials >> Navbar.vue file and add the login route.

// Navbar.js

<li class="nav-item">
   <nuxt-link :to="{ name: 'login' }" class="nav-link">
      Login
   </nuxt-link>
</li>

Switch to the browser and go to this URL: http://localhost:3000/login. You can see the form.

Step 11: Submit the login form.

We need to define the data in the form that needs to be submitted on the server. In our case, it is email and password.

// login.vue

data() {
    return {
         userForm: {
            email: '',
            password: ''
         }
     }
},

We need to define the function when the login button is clicked.

// login.vue

methods: {
   async addUser() {
       await this.$auth.login({
            data: this.userForm
       });
       this.$router.push({
            path: '/'
        });
    }
}

Our final login.vue file with the html template looks like this.

// login.vue

<template>
    <div class="container top">
        <div class="row justify-content-center">
            <div class="col-md-8">
                <div class="card">
                    <div class="card-header">Login</div>
                    <div class="card-body">
                        <form @submit.prevent="addUser">
                            <div class="form-group row">
                                <label for="email" class="col-sm-4 col-form-label text-md-right">Email</label>
                                <div class="col-md-6">
                                    <input type="email" v-model="userForm.email" class="form-control" required autofocus>
                                        <span class="invalid-feedback" role="alert">
                                            <strong></strong>
                                        </span>
                                </div>
                            </div>

                            <div class="form-group row">
                                <label for="password" class="col-md-4 col-form-label text-md-right">Password</label>

                                <div class="col-md-6">
                                    <input type="password" v-model="userForm.password" class="form-control" required>
                                        <span class="invalid-feedback" role="alert">
                                            <strong></strong>
                                        </span>
                                </div>
                            </div>

                            <div class="form-group row mb-0">
                                <div class="col-md-8 offset-md-4">
                                    <button type="submit" class="btn btn-primary">
                                        Login
                                    </button>
                                </div>
                            </div>
                        </form>
                    </div>
                </div>
            </div>
        </div>
    </div>
</template>

<script>
export default {
    data() {
        return {
            userForm: {
                email: '',
                password: ''
            }
        }
    },
    methods: {
        async addUser() {
            await this.$auth.login({
                data: this.userForm
            });
            this.$router.push({
                path: '/'
            });
        }
    }
}
</script>

<style>
.top {
    margin-top: 80px;
}
</style>

So, if the email and password are correct, it will return a user object and the token. You will also redirect to the root route of the nuxt js application, and now we need to change the navigation item based on the logged-in user and logged-out user.

Step 12: Create an auth store.

Inside the store folder, create one file called auth.js and write the following code.

// auth.js

export const getters = {
    loggedIn (state) {
        return state.loggedIn
    },
    user (state) {
        return state.user
    }
}

We have used the @nuxtjs/auth module, which has two states.

  1. loggedIn
  2. user

So, if we log in successfully, we get loggedIn to true. Otherwise, it is false.

Now, we need both of these states globally inside our nuxt.js application. We create a plugin and mixin to access both store states.

Inside the plugins folder, create one folder called mixins; inside, create one file called user.js.

Write the following code inside a user.js file.

// user.js

import Vue from 'vue'
import Vue from 'vue'
import { mapGetters } from 'vuex'

const User = {
    install (Vue, Options) {
        Vue.mixin({
            computed: {
                ...mapGetters({
                    user: 'auth/user',
                    loggedIn: 'auth/loggedIn'
                })
            }
        })
    }
}

Vue.use(User);

Register this plugin inside the nuxt.config.js file.

// nuxt.config.js

plugins: ['~plugins/bootstrap.js', '~plugins/mixins/user.js']

Okay, we have replaced the Navbar.vue file with the following one.

// Navbar.vue

<template>
    <nav class="navbar navbar-expand-sm bg-light">
        <div class="container">
            <a class="navbar-brand" href="">
                Nuxt Laravel Auth
            </a>
            <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false">
                <span class="navbar-toggler-icon"></span>
            </button>

            <div class="collapse navbar-collapse" id="navbarSupportedContent">
                <ul class="navbar-nav ml-auto">
                    <template v-if="!loggedIn">
                        <li class="nav-item">
                            <nuxt-link :to="{ name: 'login' }" class="nav-link">
                                Login
                            </nuxt-link>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link" href="">Register</a>
                        </li>
                    </template>
                    <template v-if="loggedIn">
                        <li class="nav-item">
                            <a class="nav-link" @click.prevent="logout" href="#">
                                    Logout
                            </a>  
                        </li>
                    </template>
                </ul>
            </div>
        </div>
    </nav>
</template>
<script>
export default {
    
}
</script>

Step 13: Create a Register form.

Create one page called to register.vue inside the pages folder and add the following code.

// register.vue

<template>
    <div class="container top">
    <div class="row justify-content-center">
        <div class="col-md-8">
            <div class="card">
                <div class="card-header">Register</div>

                <div class="card-body">
                    <form @submit.prevent="registerUser">
                        <div class="form-group row">
                            <label for="name" class="col-md-4 col-form-label text-md-right">Name</label>

                            <div class="col-md-6">
                                <input type="text" class="form-control" v-model="userForm.name" required autofocus>
                                    <span class="invalid-feedback" role="alert">
                                        <strong></strong>
                                    </span>
                            </div>
                        </div>

                        <div class="form-group row">
                            <label for="email" class="col-md-4 col-form-label text-md-right">Email</label>

                            <div class="col-md-6">
                                <input type="email" class="form-control" v-model="userForm.email" required>
                                    <span class="invalid-feedback" role="alert">
                                        <strong></strong>
                                    </span>
                            </div>
                        </div>

                        <div class="form-group row">
                            <label for="password" class="col-md-4 col-form-label text-md-right">Password</label>
                            <div class="col-md-6">
                                <input type="password" class="form-control" v-model="userForm.password" required>
                                    <span class="invalid-feedback" role="alert">
                                        <strong></strong>
                                    </span>
                            </div>
                        </div>
                        <div class="form-group row mb-0">
                            <div class="col-md-6 offset-md-4">
                                <button type="submit" class="btn btn-primary">
                                    Register
                                </button>
                            </div>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
</template>

<script>
export default {
    data() {
        return {
            userForm: {
                name: '',
                email: '',
                password: ''
            }
        }
    },
    methods: {
        async registerUser() {
            await this.$axios.post('register', this.userForm);
            this.$auth.login({
                data: {
                    email: this.userForm.email,
                    password: this.userForm.password
                }
            })
            this.$router.push({
                path: '/'
            });
        }
    }
}
</script>

<style>
.top {
    margin-top: 80px;
}
</style>

So, now you can successfully register and log in to our Nuxt.js application.

Step 14: Create Logout functionality.

At the Laravel server, we must define the route and function to destroy the token.

// api.php

Route::post('/logout', 'Auth\AuthController@logout');

Add the logout function inside the AuthController.php file.

// AuthController.php 

public function logout()
{
     auth()->logout();
}

We need to define the logout endpoint inside a nuxt.config.js file.

// nuxt.config.js

auth: {
    strategies: {
      local: {
        endpoints: {
          login: { url: 'login', method: 'post', propertyName: 'meta.token' },
          user: { url: 'user', method: 'get', propertyName: 'data' },
          logout: { url: 'logout', method: 'post' }
        }
      }
    }
  },

Add the logout function on the client-side inside Navbar.vue file.

// Navbar.vue

<template>
    <nav class="navbar navbar-expand-sm bg-light">
        <div class="container">
            <a class="navbar-brand" href="">
                Nuxt Laravel Auth 
            </a>
            <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false">
                <span class="navbar-toggler-icon"></span>
            </button>

            <div class="collapse navbar-collapse" id="navbarSupportedContent">
                <ul class="navbar-nav ml-auto">
                    <template v-if="!loggedIn">
                        <li class="nav-item">
                            <nuxt-link :to="{ name: 'login' }" class="nav-link">
                                Login
                            </nuxt-link>
                        </li>
                        <li class="nav-item">
                            <nuxt-link :to="{ name: 'register' }" class="nav-link">
                                Register
                            </nuxt-link>
                        </li>
                    </template>
                    <template v-if="loggedIn">
                        <li class="nav-item">
                            <a class="nav-link" @click.prevent="logout" href="#">
                                    Logout
                            </a>  
                        </li>
                    </template>
                </ul>
            </div>
        </div>
    </nav>
</template>
<script>
export default {
    methods: {
        logout() {
            this.$auth.logout();
        }
    }
}
</script>

You can log out, and it will destroy the token, and you will successfully be logged out. Your navigation items will be changed to log in and register.

Change the pages >> index.vue file to display the current user’s name.

// index.vue

<template>
  <div class="container">
    <p v-if="loggedIn">
      Hello {{ user.name }}
    </p>
    <p v-if="!loggedIn">
      Please sign in
    </p>
  </div>
</template>

<script>

export default {
  
}
</script>

Nuxt js authentication

If we log out, we can see the same page, but the text and navigation items will be changed.

Vue Laravel Auth

That’s it for this tutorial.

Github Code For Laravel Server

Now, the following code is for the Nuxt.js project.

Github Code For Nuxt.js Client

16 thoughts on “Nuxt.js Laravel Authentication: Everything You Need to Know”

  1. Great article. Thank you.
    This article is helped for me.
    And one last thing, I encountered the error in the user.js.
    I think that `import Vue from ‘vue’` is duplicate.

    Reply
  2. Hi, What is he URL pointing here in user.js “`user: ‘auth/user’, loggedIn: ‘auth/loggedIn’“` ? i cant find any /auth folder or url

    Reply
  3. What`s is this?? This tutorial is not correct, sorry for my english, but i am not understanding what you are write? Look like this:
    public function user(Request $request)
    {
    return new UserResource($request->user());
    }

    For what?

    Reply
    • Actually, you are not understanding. I have used the Laravel resource for API. First, check out on official Laravel documentation and then you will realize what I have done. If this is out of your syllabus that does not mean this is not right.

      Reply
  4. I got cors error :

    Access to XMLHttpRequest at ‘http://laravel-server.test/api/login’ from origin ‘http://localhost:3000’ has been blocked by CORS policy: Response to preflight request doesn’t pass access control check: The ‘Access-Control-Allow-Origin’ header contains multiple values

    I used Laravel 5.7.19 ..

    I tried to change the localhost to ‘dist.test’ which is running in dist folder with valet.

    it caused same error.

    Is there any tip for this error?..

    .

    Reply
  5. Actually I downloaded your source code and composed and run too.. but it failed again with same error

    ‘Access to XMLHttpRequest at ‘http://laravelnuxtapi.test/api/login’ from origin ‘http://localhost:3000’ has been blocked by CORS policy: Response to preflight request doesn’t pass access control check: The ‘Access-Control-Allow-Origin’ header contains multiple values ‘http://localhost:3000, *’, but only one is allowed.’

    Can you give tips?

    Reply
  6. Could be awesome to update this with Nuxt Social Auth with the official Nuxt auth module.
    Nothing found out there.

    Reply
  7. Hello, This article is helping me so much.
    But I have a little problem here, in google chrome console I got a message that says:
    “[vuex] unknown getter: auth/loggedIn”.
    Could you help me with that please.
    Thanks

    Reply
  8. Hello Krunal,

    First thank you, it’s a very nice tutorial !

    I am new with nuxtjs and laravel. I have a problem at the login step in the nuxt app.
    I have error with token access when I try to login.

    TypeError: Cannot use ‘in’ operator to search for ‘meta.token’ in

    Everything work fine on postman, I get the token in the meta obj when login
    Here’s my nuxt config

    export default {
    mode: ‘universal’,
    head: {
    title: process.env.npm_package_name || ”,
    meta: [
    { charset: ‘utf-8’ },
    { name: ‘viewport’, content: ‘width=device-width, initial-scale=1’ },
    { hid: ‘description’, name: ‘description’, content: process.env.npm_package_description || ” }
    ],
    link: [
    { rel: ‘icon’, type: ‘image/x-icon’, href: ‘/favicon.ico’ }
    ]
    },
    loading: { color: ‘#fff’ },
    css: [
    ],
    plugins: [
    ],
    buildModules: [
    ‘@nuxtjs/eslint-module’
    ],
    modules: [
    ‘nuxt-buefy’,
    ‘@nuxtjs/axios’,
    ‘@nuxtjs/auth’
    ],
    axios: {
    baseUrl: “http://127.0.0.1:8000/api”
    },
    auth: {
    strategies: {
    local: {
    endpoints: {
    login: {
    url: ‘login’,
    method: ‘post’,
    propertyName: ‘meta.token’
    },
    user: {
    url: ‘user’,
    method: ‘get’,
    propertyName: ‘data’
    },
    logout: {
    url: ‘logout’,
    method: ‘post’
    }
    }
    }
    }
    },
    build: {
    extend (config, ctx) {
    }
    }
    }

    If someone have the same problem or the solution, it would be nice ! :p

    Have a good day

    Reply

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.