Nuxt js Laravel Authentication Tutorial With Example is the today’s leading topic. We use Nuxt.js as a frontend and Laravel as a backend. We create an API to that authenticate the user sent from the client. In return, we send a JSON Web Token. After signing in, we will send a JWT token with the request to verify in the server that user is valid and it needs to assign the proper resources he has requested. We use Tymon laravel package to generate the token in the server side.

Nuxt js Laravel Authentication Tutorial

We start our project by installing two projects.

Laravel Nuxt.js

Step 1: Install Laravel and Nuxt.js.

Let us install Laravel 5.6 using the following command. I have used Laravel Valet.

laravel new laravel-server

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

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

yarn global add @vue/cli-init

Now, install the starter template.

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

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

cd nuxt-client npm install

Now, 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/. You can see something like below.

Step 2: Configure Laravel 5.6.

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

cd laravel-server code .

Configure the database inside the .env file.

Migrate the database table using the following command.

php artisan migrate

Now, we are using Laravel as an API, so we do not need web routes in our project. Simply client makes a particular request, and laravel server returns a JSON response. That is it. Nothing more complicated.

So, we do not need any of the controller files that reside in 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 functions like Register, Login, and, Logout function 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 Laravel project root, type the following command. 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 version of the package.

"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" },

Now, type the following command to update the package.

composer update

It will update the package.

Configure the Tymon package.

First, go to the User.php model, and that model needs to implement the JWTSubject interface.

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

Write the following code inside 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 []; } }

Now, 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

Now, generate the jwt secret using the following command.

php artisan jwt:secret

Now, 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.

Now, we have created the AuthController.php file. So, write the first route inside routes >> api.php file. Remove existing code in an api.php file.

<?php // api.php Route::post('register', 'Auth\AuthController@register')->name('register');

Now, write the code inside 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, first, the request will be verified again the server side validation and then create a User in the database and return that user.

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

php artisan make:resource UserResource

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

We need to modify the UserResource.php file and edit the function toArray(). We need to return an array that contains only properties that client needs to display at the front end side. 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 ]; } }

Now, import UserResource.php file inside 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); } }

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

Now, we can see that the user is created. Next step is that we need to sign in that user in our application and generate the JWT Token and send that token to the client. So we send the User object as well as 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, then it will generate a JWT token and send back to the client. We can test in the Postman by sending another request to the server.

Step 5: Create Login Functionality.

Okay, so 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 ] ]); }

So, if the requested user is valid, then it will send a token to the client.

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

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

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

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

Step 6: Install CORS module.

When we submit the request from the client side, we get an error inside browser called cross-site request origin. We get this error because our Nuxt.js application is running on PORT: 3000 and Laravel server is running on 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 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']

Also, 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)/ }) } } },

So, 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'] }

Now, inside 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 Layout inside a Nuxt project.

Now, inside layouts folder, create one more folder called partials and inside that, create one Vue component called Navbar.js. Write the following code inside 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. You can see, we have our navbar with the items like register, login, logout, 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.

@nuxjs/axios @nuxtjs/auth

yarn add @nuxtjs/axios @nuxtjs/auth # or npm install @nuxtjs/axios @nuxtjs/auth --save

Now, register these modules inside the nuxt.config.js file.

// nuxtjs.config.js loading: { color: '#3B8070' }, modules: ['@nuxtjs/auth', '@nuxtjs/axios'],

Now, 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: {} } } } },

So, here, we have defined the baseURL for a laravel-server API and also define 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 pages directory. 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>

Now, 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.

Now, 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: '' } } },

Also, 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: '/' }); } }

So, 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 then it will return a user object as well as 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 logged in user and logged out user.

Step 12: Create an auth store.

Inside 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 @nuxtjs/auth module, which two states.

loggedIn user

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

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

Inside plugins folder, create one folder called mixins and inside that 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);

Now, register this plugin inside the nuxt.config.js file.

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

Okay, now we replace 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 Register form.

Now, create one page called register.vue inside 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 logged in to our Nuxt.js application.

Step 14: Create Logout functionality.

At the Laravel server, we need to define the route as well as function to destroy the token.

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

Now, add the logout function inside AuthController.php file.

// AuthController.php public function logout() { auth()->logout(); }

Also, 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 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>

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

Also, 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>

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

Finally, Nuxt js Laravel Authentication Tutorial is over.

I know there are still so much to add in this project like validation message display at a client side and if the user is logged in then we need to redirect to the home page and not logged in a page if try to access the logged in page, but for this tutorial, it is enough. Already this tutorial is getting big and big. So we will do it in future tutorials.

So we have covered the following things in this Nuxt js Laravel Authentication Tutorial.

Registering the User. Log in the User. Display the user information. Logout the user.

Github Code For Laravel Server

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

Github Code For Nuxt.js Client