Laravel 9 Vuejs api Authentication using Passport Tutorial Example

Throughout this Laravel 9 Vue.js api Authentication using Passport tutorial, you will learn how to create a secure non-spa vue authentication system in laravel applicationusing Passport pacakge. In this tutorial, we will learn to create register, login, logout and secure auth RESTful Authentication API with Passport Package in Laravel 9 and vuejs by following all the imperatives needed to be followed.

This tutorial will teach you how to build and secure your Laravel back-end API using Laravel passport and how to create auth system in laravel with token based api request as well. Laravel 9 Passport takes care of security and allows you to create Auth Token to provide authentication to users.

To secure this application, we will install Laravel Passport and generate an access token for each user after authentication. This will allow such users to have access to some of the secured endpoints.

We will lean how to set the secure token in vuejs and how we send the token in event request for backend. You can use this example in laravel 5, laravel 6, laravel 7, laravel 8 or laravel 9 with vue2 and vue3 version easily. Le’ts see the step by step of laravel 9 and vuejs authentication process using passport from scratch.

Install Laravel

Open terminal further run below command to manifest a new laravel project, ignore this step if project is already installed:

composer create-project laravel/laravel laravel-vue-passport-auth 

Connect Database to App

This step explains how to make database connection by adding database name, username and password in .env config file of your project:

DB_CONNECTION=mysql
DB_HOST=localhost
DB_PORT=3306
DB_DATABASE=#your database name
DB_USERNAME=#database username
DB_PASSWORD=#database password

Install And Configure Laravel Passport

On an impulse, the second step leads us to install the passport package through Composer package manager. Without further ado run the following command in your terminal.

composer require laravel/passport

Once the installation is complete, a new migration file containing the tables needed to store clients and access tokens will have been generated for your application. Run the following command to migrate your database:

php artisan migrate

Next, to create the encryption keys needed to generate secured access tokens, run the command below:

php artisan passport:install

Immediately after the installation process from the preceding command is finished, add the Laravel\Passport\HasApiTokens trait to your App\Models\User model as shown here:

<?php

namespace App\Models;

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
// use Laravel\Sanctum\HasApiTokens; // comment this
use Laravel\Passport\HasApiTokens; // include this

class User extends Authenticatable
{
    use HasApiTokens, HasFactory, Notifiable;

    /**
     * The attributes that are mass assignable.
     *
     * @var array<int, string>
     */
    protected $fillable = [
        'name',
        'email',
        'password',
    ];

    /**
     * The attributes that should be hidden for serialization.
     *
     * @var array<int, string>
     */
    protected $hidden = [
        'password',
        'remember_token',
    ];

    /**
     * The attributes that should be cast.
     *
     * @var array<string, string>
     */
    protected $casts = [
        'email_verified_at' => 'datetime',
    ];
}

Next, open app/Providers/AuthServiceProvider.php file and register the registerPolicies() method inside the boot() function, It will evoke the required routes.

app/Providers/AuthServiceProvider.php
<?php

namespace App\Providers;

use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Gate;
use Laravel\Passport\Passport; // add this

class AuthServiceProvider extends ServiceProvider
{
    /**
     * The policy mappings for the application.
     *
     * @var array<class-string, class-string>
     */
    protected $policies = [
        'App\Models\Model' => 'App\Policies\ModelPolicy',
    ];

    /**
     * Register any authentication / authorization services.
     *
     * @return void
     */
    public function boot()
    {
        $this->registerPolicies();

        Passport::routes(); // Add this
    }
}

After registering Passport::routes(), Laravel Passport is almost ready to handle all authentication and authorization processes within your application.

Finally, for your application to be ready to use Passport’s TokenGuard

to authenticate any incoming API requests, open the config/auth configuration file and set the driver option of the api authentication guard to passport:

config\auth.php

<?php

return [

    /*
    |--------------------------------------------------------------------------
    | Authentication Defaults
    |--------------------------------------------------------------------------
    |
    | This option controls the default authentication "guard" and password
    | reset options for your application. You may change these defaults
    | as required, but they're a perfect start for most applications.
    |
    */

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

    /*
    |--------------------------------------------------------------------------
    | Authentication Guards
    |--------------------------------------------------------------------------
    |
    | Next, you may define every authentication guard for your application.
    | Of course, a great default configuration has been defined for you
    | here which uses session storage and the Eloquent user provider.
    |
    | All authentication drivers have a user provider. This defines how the
    | users are actually retrieved out of your database or other storage
    | mechanisms used by this application to persist your user's data.
    |
    | Supported: "session"
    |
    */

    'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],
        'api' => [
            'driver' => 'passport', // set this to passport
            'provider' => 'users',
            'hash' => false,
        ],
    ],

    /*
    |--------------------------------------------------------------------------
    | User Providers
    |--------------------------------------------------------------------------
    |
    | All authentication drivers have a user provider. This defines how the
    | users are actually retrieved out of your database or other storage
    | mechanisms used by this application to persist your user's data.
    |
    | If you have multiple user tables or models you may configure multiple
    | sources which represent each model / table. These sources may then
    | be assigned to any extra authentication guards you have defined.
    |
    | Supported: "database", "eloquent"
    |
    */

    'providers' => [
        'users' => [
            'driver' => 'eloquent',
            'model' => App\Models\User::class,
        ],

        // 'users' => [
        //     'driver' => 'database',
        //     'table' => 'users',
        // ],
    ],

    /*
    |--------------------------------------------------------------------------
    | Resetting Passwords
    |--------------------------------------------------------------------------
    |
    | You may specify multiple password reset configurations if you have more
    | than one user table or model in the application and you want to have
    | separate password reset settings based on the specific user types.
    |
    | The expire time is the number of minutes that each reset token will be
    | considered valid. This security feature keeps tokens short-lived so
    | they have less time to be guessed. You may change this as needed.
    |
    */

    'passwords' => [
        'users' => [
            'provider' => 'users',
            'table' => 'password_resets',
            'expire' => 60,
            'throttle' => 60,
        ],
    ],

    /*
    |--------------------------------------------------------------------------
    | Password Confirmation Timeout
    |--------------------------------------------------------------------------
    |
    | Here you may define the amount of seconds before a password confirmation
    | times out and the user is prompted to re-enter their password via the
    | confirmation screen. By default, the timeout lasts for three hours.
    |
    */

    'password_timeout' => 10800,

];

Create Authentication controllers

Let us take another imperative in the consideration and, on the same impetus, execute the following command. It will create a new controller in our laravel app to create a login and registration REST API.

php artisan make:controller Api/AuthController

Controller is the quintessential file in Laravel application development. So, without further insert the given below code in AuthController.php file.

app\Http\Controllers\Api\AuthController.php

<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Auth;
use App\Models\User;

class AuthController extends Controller
{
    public function register(Request $request)
    {
        $requestData = $request->all();
        $validator = Validator::make($requestData,[
            'name' => 'required|max:55',
            'email' => 'email|required|unique:users',
            'password' => 'required|confirmed'
        ]);

        if ($validator->fails()) {
            return response()->json([
                'errors' => $validator->errors()
            ], 422);
        }

        $requestData['password'] = Hash::make($requestData['password']);

        $user = User::create($requestData);

        return response([ 'status' => true, 'message' => 'User successfully register.' ], 200);
    }

    public function login(Request $request)
    {
        $requestData = $request->all();
        $validator = Validator::make($requestData,[
            'email' => 'email|required',
            'password' => 'required'
        ]);

        if ($validator->fails()) {
            return response()->json([
                'errors' => $validator->errors()
            ], 422);
        }

        if(! auth()->attempt($requestData)){
            return response()->json(['error' => 'UnAuthorised Access'], 401);
        }

        $accessToken = auth()->user()->createToken('authToken')->accessToken;

        return response(['user' => auth()->user(), 'access_token' => $accessToken], 200);
    }

    public function me(Request $request)
    {
        $user = $request->user();

        return response()->json(['user' => $user], 200);
    }

    public function logout (Request $request)
    {
        $token = $request->user()->token();
        $token->revoke();
        $response = ['message' => 'You have been successfully logged out!'];
        return response($response, 200);
    }
}

Update Routes File

Open routes/web.php file and add below routes on it. The below code is work for api routes when we use use api routes we need to update something just like below code.

<?php

use Illuminate\Support\Facades\Route;

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
*/
 
Route::get('{any}', function () {
    return view('layouts.app');
})->where('any', '.*');

Now, we will define API routes. Go to routes/api.php file and declare the foundational code.

routes\api.php

<?php

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\Api\AuthController;

/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| is assigned the "api" middleware group. Enjoy building your API!
|
*/

Route::post('register', [AuthController::class, 'register']);
Route::post('login', [AuthController::class, 'login']);

Route::middleware('auth:api')->group(function () {
    Route::post('/logout', [AuthController::class, 'logout']);
});

Process for Authentication System in VueJs

The backend code using laravel passport is done, Now we need to create the frontend code in vue for making login, logout and after set the token how we show the dashboard and then we send the token based api request to backend.

Initiate Vue in Laravel 9

First run composer command to install Vue UI in laravel, it will manifest vue laravel scaffold.

composer require laravel/ui

Next run following command

php artisan ui vue

Now we need to install npm package with the follow commadn.

npm install

After that, use the command to install the vue router and vue axios packages. These packages are used to consume Laravel CRUD APIs.

npm install vue-router vue-axios

Note: If you got the router issue then please install the router 3 version. I noticed when we install the laravel 9 then we have errors of vue router so, we have install the vue router 3 version here.

npm install vue-router@3

To set up a vue application in Laravel, you have to create a layouts folder in the resources/views directory and create an app.blade.php file within the layouts folder.

Place below code in resources/views/layouts/app.blade.php file:

<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="csrf-token" value="{{ csrf_token() }}" />

    <title>Vue JS CRUD Operations in Laravel</title>

    <link href="{{ asset('css/app.css') }}" rel="stylesheet">
</head>

<body>
    <div id="app"></div>
    <script src="{{ asset('js/app.js') }}"></script>
</body>

</html>

Create Vue Auth Components

Next we add app.vue inside resources js directory which will show menues and we initiate the router view here.

So, create app.vue file in resources/js folder, put the below code in resources/js/app.vue file:

resources\js\app.vue

<template>
    <div class="container">
        <nav class="navbar navbar-expand-lg navbar-light bg-light">
            <div class="collapse navbar-collapse">
                <div class="navbar-nav" v-if="loggedUser">
                    <h5>Dashboard</h5>
                    <a href="javascript:void(0)" @click="logout()" class="nav-item nav-link ml-3">Logout</a>
                </div>
                <div v-else>
                    <router-link to="/login">Login</router-link>
                    <router-link to="/register">Register</router-link>
                </div>
            </div>
        </nav>
        <router-view> </router-view>
    </div>
</template>

<script>
    import Auth from './Auth.js';
    export default {
        data() {
            return {
                loggedUser: this.auth.user
            };
        },
        mounted() {
            console.log(this.auth.user);
        },
        methods: {
            logout() {
                this.axios.post('http://127.0.0.1:8000/api/logout')
                .then(({data}) => {
                    Auth.logout(); //reset local storage
                    this.$router.push('/login');
                })
                .catch((error) => {
                    console.log(error);
                });
            }
        }
    }
</script>

Now we create below three components inside resources/js/components directory.

  • login.vue
  • register.vue
  • dashboard.vue

First open resources\js\components\register.vue file and put below code on it.

<template>
    <div>
        <h1>Register</h1>
        <div>
            <label for="name">Name</label>
            <input type="text" v-model="user.name">
        </div>
        <div>
            <label for="email">Email</label>
            <input type="text" v-model="user.email">
        </div>
        <div>
            <label for="password">Password</label>
            <input type="password" v-model="user.password">
        </div>
        <div>
            <label for="password_confirmation">Confirm Password</label>
            <input type="password" v-model="user.password_confirmation">
        </div>
        <button @click="register()">Register</button>
    </div>
</template>

<script>
    export default {
        data() {
            return {
                user: {
                    name: '',
                    email: '',
                    password: '',
                    password_confirmation: ''
                }
            };
        },

        methods: {
            register() {
                console.log(this.user);
                this.axios.post('http://127.0.0.1:8000/api/register', this.user)
                    .then(({data}) => {
                        this.$router.push('/login');
                    })
                    .catch((error) => {
                        console.log(error);
                    });
            }
        }
    }
</script>

Place code in resources/js/components/login.vue file:

<template>
    <div>
        <h1>Login</h1>
        <div>
            <label for="email">Email</label>
            <input type="email" v-model="user.email">
        </div>
        <div>
            <label for="password">Password</label>
            <input type="password" v-model="user.password">
        </div>
        <button @click="login">Login</button>
    </div>
</template>

<script>
    import Auth from '../Auth.js';

    export default {
        data() {
            return {
                user: {
                    email: '',
                    password: '',
                }
            };
        },

        methods: {
            login() {
                this.axios.post('http://127.0.0.1:8000/api/login', this.user)
                    .then(({data}) => {
                        Auth.login(data.access_token,data.user); //set local storage
                        this.$router.push('/dashboard');
                    })
                    .catch((error) => {
                        console.log(error);
                    });
            }
        }
    }
</script>

One more open resources/js/components/dashboard.vue template and add the below code:

<template>
    <div>
        <h1>Dashboard Dashboard</h1>
        <h4>The logged in user details Here</h4><br>
        <p> {{user.name}}</p>
        <p> {{user.email}}</p>
    </div>
</template>
<script>
    export default {
        data () {
            return {
                user: this.auth.user
            }
        },
        created() {
            // console.log(this.auth.user);
        }
    }
</script>

Create Vue Routes for Laravel Vue Auth

Now we create new file routes.js inside resources/js directory, and we will add the code in the resources/js/routes.js file:

import Vue from 'vue';
import Auth from './Auth.js';
import VueRouter from 'vue-router';
Vue.use(VueRouter);

import Login from './components/login.vue';
import Register from './components/register.vue';
import Dashboard from './components/dashboard.vue';

const routes = [
    {
        path: '/login',
        component: Login,
        name: "Login"
    },
    {
        path: '/register',
        component: Register,
        name: "Register"
    },
    {
        path: '/dashboard',
        component: Dashboard,
        name: "Dashboard",
        meta: {
            requiresAuth: true
        }
    }
];

 const router = new VueRouter({
     mode: 'history',
     routes: routes
 });

router.beforeEach((to, from, next) => {
    if (to.matched.some(record => record.meta.requiresAuth) ) {
        if (Auth.check()) {
            next();
            return;
        } else {
            router.push('/login');
        }
    } else {
        next();
    }
});

export default router;

Create Auth helper file for localstorage

Now we create new file Auth.js inside resources/js directory, and we will add the code in the resources/js/Auth.js file:

import axios from 'axios';

class Auth {
    constructor () {
        this.token = window.localStorage.getItem('token');
        let userData = window.localStorage.getItem('user');
        this.user = userData ? JSON.parse(userData) : null;

        if (this.token) {
            axios.defaults.headers.common['Authorization'] = 'Bearer ' + this.token;
        }
    }
    login (token, user) {
        window.localStorage.setItem('token', token);
        window.localStorage.setItem('user', JSON.stringify(user));
        axios.defaults.headers.common['Authorization'] = 'Bearer ' + token;

        this.token = token;
        this.user = user;
    }
    check () {
        return !! this.token;
    }
    logout () {
        // window.localStorage.clear();
        window.localStorage.removeItem('token');
        window.localStorage.removeItem('user');
        this.user = null;
    }
}
export default new Auth();

Include Dependencies to app.js

/**
 * First we will load all of this project's JavaScript dependencies which
 * includes Vue and other libraries. It is a great starting point when
 * building robust, powerful web applications using Vue and Laravel.
 */

require('./bootstrap');
import Vue from 'vue'; // if this is not work add this =>  window.Vue = require('vue');

import axios from 'axios';
import VueAxios from 'vue-axios';
import Auth from './Auth.js';

Vue.prototype.auth = Auth;
Vue.use(VueAxios, axios);

import App from './app.vue';
import router from './routes';

const app = new Vue({
    el: '#app',
    router,
    render: h => h(App),
});

Run Development Server & Test

After the all requiremets of laravel 8 vue js crud now we run the npm run watch file which is initialise our vue files and show success. After that we run the serve or you can use your virtual host domain url here.

npm run watch
php artisan serve

If not use below code

http://127.0.0.1:8000/

If you getting Error: Cannot find module ‘webpack/lib/rules/DescriptionDataMatcherRulePlugin’ Require stack error message then you need to update your vue-loader

npm update vue-loader

Now Laravel Vue js Crud operation hopefully completed with this beautiful article. If you have any question or query please let me know in comment box. Feel free for more upate follow us on social networks.

5 thoughts on “Laravel 9 Vuejs api Authentication using Passport Tutorial Example”

  1. hye. i got error when i tried to npm run watch . and it said ,,

    Can’t resolve ‘vue-axios’ in ‘C:\Users\aminh\vuetraining\laravelvuepassport\resources\js’

    Reply

Leave a Comment