laravel 9 rest api authentication with vue 3 composition api

In this section we will create laravel rest api auth with passport and frontend we will using vue 3 composition api.


Tool Use

Laravel 9

Laravel Passport

Tailwind CSS

Vue 3 Composition Api

Vite Tool

Vue 3 Axios

Vue Router


Create Laravel Project

Install fresh laravel app and connect to mysql database.

composer create-project --prefer-dist laravel/laravel laravel-api


Install & Setup Passport

Install Passport via the Composer package manager:

composer require laravel/passport

Migrate database

php artisan migrate

Install passport client secret key

php artisan passport:install


Setup passport HasApiTokens traits in user modal,

app/Models/User.php

<?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;
use Laravel\Passport\HasApiTokens;

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, you should call the Passport::routes method within the boot method of your App\Providers\AuthServiceProvider.

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;

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();

        if (! $this->app->routesAreCached()) {
            Passport::routes();
        }
    }
}

Next, you need to set api driver for passport.

config/auth.php

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


Create Api Controller & Routes

Run below command to create controller within api folder.

php artisan make:controller Api/AuthController 


app/Http/Controllers/Api/AuthController.php

<?php

namespace App\Http\Controllers\Api;

use App\Models\User;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Symfony\Component\HttpFoundation\Response;
use Illuminate\Validation\Rules;


class AuthController extends Controller
{
    public function login(Request $request)
    {
        if (auth()->attempt($request->all())) {
            return response([
                'user' => auth()->user(),
                'access_token' => auth()->user()->createToken('authToken')->accessToken
            ], Response::HTTP_OK);
        }


        return response([
            'message' => 'This User does not exist'
        ], Response::HTTP_UNAUTHORIZED);
    }


    public function register(Request $request)
    {
        $request->validate([
            'name' => 'required|string|max:255',
            'email' => 'required|string|email|max:255|unique:users',
            'password' => ['required', 'confirmed', Rules\Password::defaults()],
        ]);
        $user = User::create([
            'name' => $request->name,
            'email' => $request->email,
            'password' => Hash::make($request->password)
        ]);


        return response($user, Response::HTTP_CREATED);
    }
}

routes/api.php

<?php

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

/*
|--------------------------------------------------------------------------
| 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('login', [AuthController::class, 'login']);
Route::post('register', [AuthController::class, 'register']);

Run laravel server and leave it.

php artisan serve



Install & Setup Vue 3 Composition Api Authentication with Laravel Rest Api

Create vue 3 project.

npm init vue@latest

Select your requirements.

Vue.js - The Progressive JavaScript Framework
 Project name:  frontend
 Add TypeScript?  No / Yes
 Add JSX Support?  No / Yes
 Add Vue Router for Single Page Application development?  No / Yes
 Add Pinia for state management?  No / Yes
 Add Vitest for Unit Testing?  No / Yes
 Add Cypress for both Unit and End-to-End testing?  No / Yes
 Add ESLint for code quality?  No / Yes
 Add Prettier for code formatting?  No / Yes
Scaffolding project in /vue-project/frontend...
Done. Now run:
 cd frontend
 npm install
npm run dev


Install axios

run below command to install vue-axios

npm i vue-axios


Install Tailwind CSS in Vue 3

How to Install Tailwind CSS in Vue 3

or

Read Tailwind Official Doc


Set Axios Path in vue 3

Setup Api path in main.js using axios.

src/main.js

import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import './index.css'
import axios from 'axios'

axios.defaults.baseURL = 'http://localhost:8000/api/';
axios.defaults.headers['Authorization'] = `Bearer ${localStorage.getItem('token')}`;

const app = createApp(App)

app.use(router)

app.mount('#app')


Create vue 3 route file

src/router/index.js

import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'
import Login from '../views/auth/Login.vue'
import Register from '../views/auth/Register.vue'


const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [
    {
      path: '/',
      name: 'home',
      component: HomeView
    },
    {
      path: '/login',
      name: 'login',
      component: Login
    },
    {
      path: '/register',
      name: 'register',
      component: Register
    },
    {
      path: '/about',
      name: 'about',
      // route level code-splitting
      // this generates a separate chunk (About.[hash].js) for this route
      // which is lazy-loaded when the route is visited.
      component: () => import('../views/AboutView.vue')
    }
  ]
})

export default router


Setup vue 3 App file

Create Navbar file and add route link.

src/components/Navbar.vue

<template>
  <nav class="container flex justify-around py-8 mx-auto bg-white border">
    <div>
      <h3 class="text-2xl font-medium text-blue-500">LOGO</h3>
    </div>
    <div class="flex items-center space-x-8">
      <RouterLink to="/">Home</RouterLink>
      <RouterLink to="/about">About</RouterLink>
      <RouterLink to="/login">Login</RouterLink>
      <RouterLink to="/register">Register</RouterLink>
      <button @click="Logout">Logout</button>
    </div>
  </nav>
</template>

<script>
import { useRouter } from 'vue-router';
export default {
  setup() {
    const router = useRouter();
    const Logout = () => {
      localStorage.clear();
      router.push({ path: '/login' });
    };
    return { Logout };
  },
};
</script>


src/App.vue

<script setup>
import { RouterLink, RouterView } from 'vue-router';
import Navbar from '@/components/Navbar.vue';

</script>

<template>
  <div>
    <Navbar />
  </div>
  <RouterView />
</template>


Setup Authentication with Vue 3 Composition Api

src/views/auth/Register.vue

<script>
import { ref } from 'vue';
import axios from 'axios';
import { useRouter } from 'vue-router';

export default {
  name: 'Register',
  setup() {
    const name = ref('');
    const email = ref('');
    const password = ref('');
    const password_confirmation = ref('');
    const router = useRouter();
    const validation = ref([]);

    const submit = async () => {
      await axios
        .post('/register', {
          name: name.value,
          email: email.value,
          password: password.value,
          password_confirmation: password_confirmation.value,
        })
        .then(() => {
          router.push({ path: '/login' });
        })
        .catch((error) => {
          validation.value = error.response.data;
        });
    };

    return {
      name,
      email,
      password,
      password_confirmation,
      submit,
      validation,
    };
  },
};
</script>

<template>
  <div class="relative flex flex-col items-center justify-center min-h-screen">
    <span class="px-2 py-2 mb-4 text-red-600 rounded shadow">
      {{ validation.message }}
    </span>
    <div class="w-full p-6 shadow bg-gray-50 lg:max-w-md">
      <h1 class="text-3xl font-semibold text-center text-purple-700">LOGO</h1>
      <form class="space-y-4" @submit.prevent="submit">
        <div>
          <label for="name" class="block text-sm text-gray-800">Name</label>
          <input
            v-model="name"
            name="name"
            type="text"
            class="block w-full px-4 py-2 mt-2 text-purple-700 bg-white border rounded-md focus:border-purple-400 focus:ring-purple-300 focus:outline-none focus:ring focus:ring-opacity-40"
          />
        </div>
        <div>
          <label for="email" class="block text-sm text-gray-800">Email</label>
          <input
            v-model="email"
            name="email"
            type="email"
            class="block w-full px-4 py-2 mt-2 text-purple-700 bg-white border rounded-md focus:border-purple-400 focus:ring-purple-300 focus:outline-none focus:ring focus:ring-opacity-40"
          />
        </div>
        <div>
          <label for="password" class="block text-sm text-gray-800"
            >Password</label
          >
          <input
            v-model="password"
            name="password"
            type="password"
            class="block w-full px-4 py-2 mt-2 text-purple-700 bg-white border rounded-md focus:border-purple-400 focus:ring-purple-300 focus:outline-none focus:ring focus:ring-opacity-40"
          />
        </div>
        <div>
          <label for="password" class="block text-sm text-gray-800"
            >Password Confirm</label
          >
          <input
            v-model="password_confirmation"
            name="password_confirmation"
            type="password"
            class="block w-full px-4 py-2 mt-2 text-purple-700 bg-white border rounded-md focus:border-purple-400 focus:ring-purple-300 focus:outline-none focus:ring focus:ring-opacity-40"
          />
        </div>
        <div>
          <button
            class="w-full px-4 py-2 tracking-wide text-white transition-colors duration-200 transform bg-purple-700 rounded-md hover:bg-purple-600 focus:outline-none focus:bg-purple-600"
          >
            Create Account
          </button>
        </div>
      </form>
      <p class="mt-8 text-xs font-light text-center text-gray-700">
        Don't have an account?

        <RouterLink
          to="/login"
          class="font-medium text-purple-600 hover:underline"
          >Login</RouterLink
        >

        >
      </p>
    </div>
  </div>
</template>
laravel 9 with vue 3 composition api auth register

laravel 9 with vue 3 composition api auth register


src/views/auth/Login.vue

<script>
import { ref } from 'vue';
import axios from 'axios';
import { useRouter } from 'vue-router';

export default {
  name: 'Login',
  setup() {
    const email = ref('');
    const password = ref('');
    const router = useRouter();

    const submit = async () => {
      const response = await axios.post('/login', {
        email: email.value,
        password: password.value,
      });
      localStorage.setItem('token', response.data.token);
      await router.push({ path: '/' });
    };

    return {
      email,
      password,
      submit,
    };
  },
};
</script>

<template>
  <div class="relative flex flex-col items-center justify-center min-h-screen">
    <div class="w-full p-6 shadow bg-gray-50 lg:max-w-md">
      <h1 class="text-3xl font-semibold text-center text-purple-700">LOGO</h1>
      <form class="space-y-4" @submit.prevent="submit">
        <div>
          <label for="email" class="block text-sm text-gray-800">Email</label>
          <input
            type="email"
            name="email"
            v-model="email"
            class="block w-full px-4 py-2 mt-2 text-purple-700 bg-white border rounded-md focus:border-purple-400 focus:ring-purple-300 focus:outline-none focus:ring focus:ring-opacity-40"
          />
        </div>
        <div>
          <label for="password" class="block text-sm text-gray-800"
            >Password</label
          >
          <input
            type="password"
            name="password"
            v-model="password"
            class="block w-full px-4 py-2 mt-2 text-purple-700 bg-white border rounded-md focus:border-purple-400 focus:ring-purple-300 focus:outline-none focus:ring focus:ring-opacity-40"
          />
        </div>
        <div>
          <button
            type="submit"
            class="w-full px-4 py-2 tracking-wide text-white transition-colors duration-200 transform bg-purple-700 rounded-md hover:bg-purple-600 focus:outline-none focus:bg-purple-600"
          >
            Login
          </button>
        </div>
      </form>
      <p class="mt-8 text-xs font-light text-center text-gray-700">
        Don't have an account?
        <RouterLink
          to="/register"
          class="font-medium text-purple-600 hover:underline"
          >Register</RouterLink
        >
      </p>
    </div>
  </div>
</template>
laravel 9 with vue 3 composition api auth login

laravel 9 with vue 3 composition api auth login

Run vue 3 server.

npm run dev


Read Also

Laravel 9 Add Simple Sidebar with Tailwind CSS Example

How to Use Carousel Slider in Laravel 9 Example

Laravel 9 Posts with Tags Many to Many Relationships Example

Laravel 9 Insert Category in Posts CRUD Example

How to Use Ckeditor 5 in Laravel 9 Vite with Tailwind CSS

Laravel 9 Simple Image Upload in Ckeditor 5 Example

Laravel 9 Flash Message Timeout and Hide Message Example

Install & Setup Markdown Editor in Laravel 9

Nuxt 3 Data Fetching Using Laravel 9 Api Example

Laravel 9 Image Upload with Preview using Tailwind CSS & Alpine JS

Laravel 9 with Tailwind CSS Form Validation Example

Laravel 9 Backend Api Connect with Vue 3 Using Axios Example

Laravel 9 Authentication with Next js Example

Laravel 9 Sanctum Authentication with Nuxt JS Example

Laravel 9 Simple Search with Pagination Example

Laravel 9 Install Setup TALL(Tailwind, Alpinejs, Livewire) Admin Panel

How to Fix and Clean Code Style in laravel 9

Laravel 9 Image File Upload Example

3 Way to Create Slug in Laravel 9 without Package

How to Add Dark Mode in Laravel 9 with Tailwind CSS