SPA Authentication using Laravel 11 Sanctum vue 3 and vite tutorial, will show you how to implement a robust authentication system in Laravel 11 and Vue.js 3 applications using the Laravel Sanctum package and Vite.
This tutorial guides you through building a RESTful Authentication API, equipping your Laravel 11 backend and Vue.js 3 frontend with essential functionalities such as user registration, login, and logout.
Laravel Vue Authentication using Sanctum and Vite SPA Example
Follow the following steps to implement SPA Authentication using Laravel 11 Sanctum and Vue 3.
- Install Laravel 11 App
- Configure Database Details
- Run Migrate Command
- Create Controller
- Configure Routes
- Install npm Pacakges
- Initiate Vue in Laravel
- Create Vue Js Auth Components
- Create Vue Routes for Laravel Vue Authentication
- Include Dependencies to app.js
- Send Authorization token in Header for Every requests
- Run Development Server
#1 Install Laravel 11 App
Before proceeding with the installation of Laravel 11, ensure that your system meets the following prerequisites:
- Laravel 11 requires PHP version 8.2 or higher. You can verify your PHP version by running php -v in your terminal or command prompt. If you don’t have PHP 8.2 installed, you’ll need to upgrade your PHP version.
- Laravel supports multiple database systems such as MySQL, PostgreSQL, SQLite, and SQL Server. In Laravel 11, they have predefined DB_CONNECTION=sqlite in the .env file, but if you are using MySQL, you will need to update it.
To install Laravel 11, run the following command in your terminal:
composer create-project laravel/laravel:^11.0 laravel-vuejs-authentication
If you prefer to install Laravel based on your PHP version, use the following command:
composer create-project laravel/laravel laravel-vuejs-authentication
Once the installation is complete, navigate to the project directory:
cd laravel-vuejs-authentication
#2 Connect Database to App
After that, add your database credentials to the .env file, such as the database name, username, and password. The .env file is located in your project’s root directory.
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=#db_name
DB_USERNAME=#db_username
DB_PASSWORD=#db_password
#3 Run Migrate Command
In Laravel’s latest version (from Laravel 8+), the Sanctum package is readily available, eliminating the need for separate installation. Simply execute the migrate command to generate predefined migration files, setting up tables necessary for Laravel Vue.js authentication with Sanctum.
php artisan migrate
Note: If you are running below the Laravel 8 version then you need to install Senctum through the Composer package manager.
#4 How to Create Controller
Now you need to create a controller to handle the Laravel vue.js API authentication system. Run the below command and it will generate a controller file in your application.
php artisan make:controller Api/AuthController
Now, open the app\Http\Controllers\Api\AuthController.php file and put the below code on it.
<?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)
{
$data = Validator::make($request->all(),[
'name' => 'required',
'email' => 'required|string|email|unique:users',
'password' => 'required|string|min:8',
]);
if ($data->fails()) {
return response()->json([
'errors' => $data->errors()
], 422);
}
$user = User::create([
'name' => $request->name,
'email' => $request->email,
'password' => Hash::make($request->password),
]);
$token = $user->createToken('auth_token')->plainTextToken;
return response()->json([
'access_token' => $token,
'token_type' => 'Bearer',
], 200);
}
public function login(Request $request)
{
$data = Validator::make($request->all(),[
'email' => 'required',
'password' => 'required',
]);
if ($data->fails()) {
return response()->json([
'errors' => $data->errors()
], 422);
}
if (!Auth::attempt($request->only('email', 'password'))) {
return response()->json([
'message' => 'Invalid login details'
], 401);
}
$user = User::where('email', $request['email'])->firstOrFail();
$token = $user->createToken('auth_token')->plainTextToken;
return response()->json([
'user' => $user,
'access_token' => $token,
'token_type' => 'Bearer',
], 200);
}
public function user(Request $request)
{
return $request->user();
}
public function logout (Request $request)
{
$request->user()->tokens()->delete();
return response()->json([
'success' => true,
'message' => 'You have been successfully logged out!',
], 200);
}
}
#5 Configure Routes for Laravel Vue.js Authentication
Open the routes/web.php file and add the below routes to it. When we use the API routes we need to update the web routes to something like this.
<?php
use Illuminate\Support\Facades\Route;
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider and all of them will
| be assigned to the "web" middleware group. Make something great!
|
*/
Route::get('{any}', function () {
return view('app');
})->where('any', '.*');
// Route::get('/', function () {
// return view('welcome');
// });
Now, open the routes/api.php file and update the Laravel Vue authentication system.
<?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 and all of them will
| be assigned to the "api" middleware group. Make something great!
|
*/
Route::post('/register', [AuthController::class, 'register']);
Route::post('/login', [AuthController::class, 'login']);
Route::middleware('auth:sanctum')->group(function () {
Route::post('/user', [AuthController::class, 'user']);
Route::post('/logout', [AuthController::class, 'logout']);
});
#6 Install npm Pacakges
Great! The backend work is completed now you need to install npm packages to create vue.js crud in Laravel app.
First, you need to generate laravel ui package, it will manifest vue laravel scaffold.
composer require laravel/ui
php artisan ui vue
Now install the npm package and then run the dev command it will reinitialize the components.
npm install && npm run dev
Next, install the vue axios using the below command.
npm install vue-axios
In Vue 2 to install Vue Router you can use npm install vue-router but we are using vue 4 version. So we will go with this command.
npm i vue-router@next
If you want to use Bootstrap then you can install the Bootstrap package using the below command.
npm install bootstrap
#7 Initiate Vue in Laravel
Now we will see how to connect blade files with vue resources js.
For this, you need to create an app.blade.php inside the resources/views directory. So, open the resources/views/app.blade.php file and update the below code on it.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Laravel Vue.js Authentication using Laravel 11 sanctum and Vite</title>
@vite('resources/css/app.css')
</head>
<body>
<div id="app"></div>
@vite('resources/js/app.js')
</body>
</html>
#8 Create Vue Js Authentication Components
Next, you’ll want to include the App.vue
file within the resources/js
directory. This file serves as the entry point for displaying menus and initializing the router view.
- Create a new file named
App.vue
in theresources/js
folder. - Open the
resources/js/App.vue
file and insert the following code:
<template>
<div class="container">
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="collapse navbar-collapse">
<div class="navbar-nav">
<router-link :to="{ name: 'Login' }" class="nav-item nav-link">Login</router-link>
<router-link :to="{ name: 'Register' }" class="nav-item nav-link">Register</router-link>
</div>
</div>
</nav>
<router-view> </router-view>
</div>
</template>
Now you need to create the vue.js authentication components. So first create a “auth” folder inside the “resources/js/components/ directory. Next, you need to create the below components inside resources/js/components directory.
- Login.vue
- Register.vue
First open resources\js\components\auth\Register.vue file and put the below code on it.
<template>
<div class="container mt-5">
<h1>Register</h1>
<div class="mb-3">
<label for="name" class="form-label">Name</label>
<input type="text" class="form-control" id="name" v-model="user.name">
<span v-if="errors.name" class="text-danger">{{ errors.name }}</span>
</div>
<div class="mb-3">
<label for="email" class="form-label">Email</label>
<input type="email" class="form-control" id="email" v-model="user.email">
<span v-if="errors.email" class="text-danger">{{ errors.email }}</span>
</div>
<div class="mb-3">
<label for="password" class="form-label">Password</label>
<input type="password" class="form-control" id="password" v-model="user.password">
<span v-if="errors.password" class="text-danger">{{ errors.password }}</span>
</div>
<div class="mb-3">
<label for="password_confirmation" class="form-label">Confirm Password</label>
<input type="password" class="form-control" id="password_confirmation" v-model="user.password_confirmation">
</div>
<button type="button" class="btn btn-primary" @click="register()">Register</button>
</div>
</template>
<script>
export default {
data() {
return {
user: {
name: '',
email: '',
password: '',
password_confirmation: '',
},
errors: {}
};
},
methods: {
register() {
this.axios.post('/api/register', this.user)
.then(({ data }) => {
this.$router.push('/login');
})
.catch((error) => {
console.log(error);
if (error.response && error.response.status === 422) {
const responseData = error.response.data;
this.errors = {};
for (const field in responseData.errors) {
if (Object.prototype.hasOwnProperty.call(responseData.errors, field)) {
this.errors[field] = responseData.errors[field][0];
}
}
}
});
}
}
}
</script>
First open resources\js\components\auth\Login.vue file and put the below code on it.
<template>
<div class="container mt-5">
<h1>Login</h1>
<div class="mb-3">
<label for="email" class="form-label">Email</label>
<input type="email" class="form-control" id="email" v-model="user.email">
<span v-if="errors.email" class="text-danger">{{ errors.email }}</span>
</div>
<div class="mb-3">
<label for="password" class="form-label">Password</label>
<input type="password" class="form-control" id="password" v-model="user.password">
<span v-if="errors.password" class="text-danger">{{ errors.password }}</span>
</div>
<span v-if="errors.other" class="text-danger">{{ errors.other }}</span>
<button type="button" class="btn btn-primary" @click="login">Login</button>
</div>
</template>
<script>
export default {
data() {
return {
user: {
email: '',
password: '',
},
errors: {}
};
},
methods: {
login() {
this.axios.post('/api/login', this.user)
.then(({data}) => {
console.log(data);
localStorage.setItem('token', data.access_token);
localStorage.setItem('user', JSON.stringify(data.user));
this.$router.push('/dashboard');
})
.catch((error) => {
console.log(error);
if (error.response && error.response.status === 422) {
const responseData = error.response.data;
this.errors = {};
for (const field in responseData.errors) {
if (Object.prototype.hasOwnProperty.call(responseData.errors, field)) {
this.errors[field] = responseData.errors[field][0];
}
}
}
});
}
}
}
</script>
Next, create Dashboard.vue inside the resources/js/components directory. Now, open resources\js\components\Dashboard.vue file and put the below code on it.
<template>
<div>
<h1>Dashboard Dashboard</h1>
<button class="btn btn-primary" @click="logout()">Logout</button>
<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: JSON.parse(localStorage.getItem('user')) || {}
}
},
methods: {
logout() {
this.axios.post('/api/logout')
.then(({data}) => {
localStorage.removeItem('token');
localStorage.removeItem('user');
this.$router.push('/login');
})
.catch((error) => {
console.log(error);
});
}
},
}
</script>
#9 Create Vue Routes for Laravel Vue Authentication
Now we create new file “routes.js” inside “resources/js” directory. Next, open the resources/js/routes.js file and place the below code on it.
import { createWebHistory, createRouter } from "vue-router";
import Dashboard from "@/components/Dashboard.vue";
import Login from "@/components/auth/Login.vue";
import Register from "@/components/auth/Register.vue";
const routes = [
{
path: "/login",
name: "Login",
component: Login,
},
{
path: "/register",
name: "Register",
component: Register,
},
{
path: "/dashboard",
name: "Dashboard",
component: Dashboard,
meta: {
requiresAuth: true
}
},
];
const router = createRouter({
history: createWebHistory(),
routes,
});
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requiresAuth) ) {
const token = localStorage.getItem('token');
if (token) {
next();
return;
} else {
router.push('/login');
}
} else {
next();
}
});
export default router;
#10 Include Dependencies to app.js
So, open the resources\js\app.js file and update your packages like this.
import './bootstrap';
import 'bootstrap/dist/css/bootstrap.min.css';
import { createApp } from 'vue';
import App from './App.vue';
import axios from './axios';
import VueAxios from 'vue-axios'
import router from './routes'
// import ExampleComponent from './components/ExampleComponent.vue';
// app.component('example-component', ExampleComponent);
createApp(App).use(router).use(VueAxios, axios).mount('#app');
#11 Send Authorization token in Headers of every required Authenticate Request
import axios from 'axios';
// axios.defaults.baseURL = 'https://api.example.com';
axios.interceptors.request.use(function (config) {
const token = localStorage.getItem('token');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
}, function (error) {
return Promise.reject(error);
});
export default axios;
#12 Vite config Code Should be (vite.config.js)
Before Laravel utilized Mix to minify JavaScript and CSS (SCSS), but in the current version, Vite is employed for this purpose. To ensure consistency, open the vite.config.js file and verify that the code remains unchanged.
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import vue from '@vitejs/plugin-vue';
export default defineConfig({
plugins: [
laravel({
input: [
'resources/css/app.css',
'resources/js/app.js',
],
refresh: true,
}),
vue({
template: {
transformAssetUrls: {
base: null,
includeAbsolute: false,
},
},
}),
],
resolve: {
alias: {
vue: 'vue/dist/vue.esm-bundler.js',
},
},
});
#11 Run Development Server
After fulfilling all the requirements for the Laravel Vue.js 3 API authentication application, proceed by running the following commands: npm run dev
and php artisan serve
.
Previously, Laravel provided the watch
command for this purpose. However, with the introduction of Vite, the script has been updated to dev
.
The dev
command initializes our JavaScript components, while the serve
command runs our application.
npm run dev
php artisan serve
Now, hit the below ur and enjoy.
http://localhost:8000/
or
http://127.0.0.1:8000/
So, guys the Laravel 11 Vuejs 3 API authentication Example is completed now.