This tutorial will guide you through setting up API token-based authentication using Laravel as the backend and Vue 3 as the frontend.
composer create-project laravel/laravel laravel-api-auth
cd laravel-api-auth
php artisan serve
Laravel 10 has built-in token abilities using Sanctum.
composer require laravel/sanctum
php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
php artisan migrate
Make sure middleware is included for API requests.
'api' => [
\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
'throttle:api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
use Laravel\Sanctum\HasApiTokens;
class User extends Authenticatable
{
use HasApiTokens, Notifiable;
}
routes/api.php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use App\Models\User;
use Illuminate\Support\Facades\Hash;
Route::post('/register', function(Request $request){
$user = User::create([
'name' => $request->name,
'email' => $request->email,
'password' => Hash::make($request->password),
]);
$token = $user->createToken('api-token')->plainTextToken;
return response()->json(['user'=>$user, 'token'=>$token]);
});
Route::post('/login', function(Request $request){
$user = User::where('email', $request->email)->first();
if(!$user || !Hash::check($request->password, $user->password)){
return response()->json(['message'=>'Invalid credentials'], 401);
}
$token = $user->createToken('api-token')->plainTextToken;
return response()->json(['user'=>$user, 'token'=>$token]);
});
Route::middleware('auth:sanctum')->get('/user', function(Request $request){
return $request->user();
});
npm create vite@latest vue-laravel-auth
cd vue-laravel-auth
npm install
npm run dev
npm install axios
npm install pinia
src/stores/auth.js
import { defineStore } from 'pinia';
import axios from 'axios';
export const useAuthStore = defineStore('auth', {
state: () => ({
user: null,
token: localStorage.getItem('token') || null,
}),
actions: {
async login(email, password){
const res = await axios.post('http://localhost:8000/api/login', { email, password });
this.user = res.data.user;
this.token = res.data.token;
localStorage.setItem('token', this.token);
axios.defaults.headers.common['Authorization'] = `Bearer ${this.token}`;
},
async register(name, email, password){
const res = await axios.post('http://localhost:8000/api/register', { name, email, password });
this.user = res.data.user;
this.token = res.data.token;
localStorage.setItem('token', this.token);
axios.defaults.headers.common['Authorization'] = `Bearer ${this.token}`;
},
logout(){
this.user = null;
this.token = null;
localStorage.removeItem('token');
delete axios.defaults.headers.common['Authorization'];
}
}
});
<script setup>
import { ref } from 'vue';
import { useAuthStore } from '../stores/auth';
const email = ref('');
const password = ref('');
const auth = useAuthStore();
const handleLogin = async () => {
try {
await auth.login(email.value, password.value);
alert('Login Successful');
} catch(e) {
alert('Invalid Credentials');
}
};
</script>
<template>
<input v-model="email" placeholder="Email" />
<input v-model="password" placeholder="Password" type="password" />
<button @click="handleLogin">Login</button>
</template>
import axios from 'axios';
const res = await axios.get('http://localhost:8000/api/user');
console.log(res.data);