294 lines
7.8 KiB
Markdown
294 lines
7.8 KiB
Markdown
# 🚀 Quick Start - Authentication System
|
|
|
|
## ✅ What's Been Set Up
|
|
|
|
Your Laravel + Vue 3 + Inertia.js application now has a complete authentication system with:
|
|
|
|
1. ✅ **Axios** - Already installed (v1.11.0)
|
|
2. ✅ **Pinia** - State management (already installed, replaces Vuex)
|
|
3. ✅ **Auth Service** - API calls to `http://localhost:8000/api/auth/login`
|
|
4. ✅ **Auth Store** - Centralized authentication state
|
|
5. ✅ **Route Guards** - Protect pages based on authentication
|
|
6. ✅ **Persistence** - Auth state survives page reloads
|
|
|
|
## 📁 Files Created
|
|
|
|
```
|
|
resources/js/
|
|
├── services/
|
|
│ └── authService.ts ← API service for auth endpoints
|
|
├── stores/
|
|
│ └── auth.ts ← Pinia store for auth state
|
|
├── middleware/
|
|
│ └── auth.ts ← Route guard middleware
|
|
├── composables/
|
|
│ └── useAuthGuard.ts ← Composables for protecting routes
|
|
└── components/
|
|
└── LoginExample.vue ← Example login component
|
|
```
|
|
|
|
## 🎯 How to Use
|
|
|
|
### 1. In Your Login Component
|
|
|
|
```vue
|
|
<script setup lang="ts">
|
|
import { useAuthStore } from '@/stores/auth';
|
|
import { router } from '@inertiajs/vue3';
|
|
import { ref } from 'vue';
|
|
|
|
const authStore = useAuthStore();
|
|
const email = ref('');
|
|
const password = ref('');
|
|
|
|
async function login() {
|
|
const success = await authStore.login({
|
|
email: email.value,
|
|
password: password.value,
|
|
remember: true
|
|
});
|
|
|
|
if (success) {
|
|
router.get('/dashboard');
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<form @submit.prevent="login">
|
|
<input v-model="email" type="email" placeholder="Email" />
|
|
<input v-model="password" type="password" placeholder="Password" />
|
|
<button type="submit" :disabled="authStore.loading">
|
|
{{ authStore.loading ? 'Logging in...' : 'Login' }}
|
|
</button>
|
|
<p v-if="authStore.error" class="error">{{ authStore.error }}</p>
|
|
</form>
|
|
</template>
|
|
```
|
|
|
|
### 2. Protect Your Dashboard
|
|
|
|
```vue
|
|
<script setup lang="ts">
|
|
import { useAuthGuard } from '@/composables/useAuthGuard';
|
|
|
|
// This will redirect to /login if not authenticated
|
|
useAuthGuard();
|
|
</script>
|
|
|
|
<template>
|
|
<div>
|
|
<h1>Protected Dashboard</h1>
|
|
</div>
|
|
</template>
|
|
```
|
|
|
|
### 3. Display User Info
|
|
|
|
```vue
|
|
<script setup lang="ts">
|
|
import { useAuthStore } from '@/stores/auth';
|
|
|
|
const authStore = useAuthStore();
|
|
</script>
|
|
|
|
<template>
|
|
<div v-if="authStore.isAuthenticated">
|
|
Welcome, {{ authStore.currentUser?.name }}!
|
|
<button @click="authStore.logout">Logout</button>
|
|
</div>
|
|
</template>
|
|
```
|
|
|
|
## 🔧 Backend Requirements
|
|
|
|
You need these Laravel API endpoints:
|
|
|
|
### Login Endpoint
|
|
```php
|
|
// POST http://localhost:8000/api/auth/login
|
|
Route::post('api/auth/login', function(Request $request) {
|
|
$credentials = $request->validate([
|
|
'email' => 'required|email',
|
|
'password' => 'required',
|
|
]);
|
|
|
|
if (Auth::attempt($credentials)) {
|
|
return response()->json([
|
|
'user' => Auth::user(),
|
|
'token' => Auth::user()->createToken('auth')->plainTextToken
|
|
]);
|
|
}
|
|
|
|
return response()->json(['message' => 'Invalid credentials'], 401);
|
|
});
|
|
```
|
|
|
|
### User Endpoint
|
|
```php
|
|
// GET http://localhost:8000/api/auth/user
|
|
Route::get('api/auth/user', function() {
|
|
return response()->json(['user' => Auth::user()]);
|
|
})->middleware('auth:sanctum');
|
|
```
|
|
|
|
### Logout Endpoint
|
|
```php
|
|
// POST http://localhost:8000/api/auth/logout
|
|
Route::post('api/auth/logout', function(Request $request) {
|
|
$request->user()->currentAccessToken()->delete();
|
|
return response()->json(['message' => 'Logged out']);
|
|
})->middleware('auth:sanctum');
|
|
```
|
|
|
|
## 🎨 Complete Working Examples
|
|
|
|
### Example 1: Simple Login Page
|
|
|
|
```vue
|
|
<script setup lang="ts">
|
|
import { useAuthStore } from '@/stores/auth';
|
|
import { useGuestGuard } from '@/composables/useAuthGuard';
|
|
import { router } from '@inertiajs/vue3';
|
|
import { ref } from 'vue';
|
|
|
|
useGuestGuard(); // Redirect to dashboard if already logged in
|
|
|
|
const authStore = useAuthStore();
|
|
const form = ref({
|
|
email: '',
|
|
password: '',
|
|
remember: false
|
|
});
|
|
|
|
async function handleSubmit() {
|
|
const success = await authStore.login(form.value);
|
|
if (success) {
|
|
router.get('/dashboard');
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<div class="login-container">
|
|
<h1>Login</h1>
|
|
|
|
<div v-if="authStore.error" class="alert alert-error">
|
|
{{ authStore.error }}
|
|
</div>
|
|
|
|
<form @submit.prevent="handleSubmit">
|
|
<div>
|
|
<label>Email</label>
|
|
<input v-model="form.email" type="email" required />
|
|
</div>
|
|
|
|
<div>
|
|
<label>Password</label>
|
|
<input v-model="form.password" type="password" required />
|
|
</div>
|
|
|
|
<div>
|
|
<label>
|
|
<input v-model="form.remember" type="checkbox" />
|
|
Remember me
|
|
</label>
|
|
</div>
|
|
|
|
<button type="submit" :disabled="authStore.loading">
|
|
{{ authStore.loading ? 'Logging in...' : 'Login' }}
|
|
</button>
|
|
</form>
|
|
</div>
|
|
</template>
|
|
```
|
|
|
|
### Example 2: Protected Dashboard
|
|
|
|
```vue
|
|
<script setup lang="ts">
|
|
import { useAuthGuard } from '@/composables/useAuthGuard';
|
|
import { useAuthStore } from '@/stores/auth';
|
|
import { router } from '@inertiajs/vue3';
|
|
|
|
useAuthGuard(); // Redirect to login if not authenticated
|
|
|
|
const authStore = useAuthStore();
|
|
|
|
async function handleLogout() {
|
|
await authStore.logout();
|
|
router.get('/login');
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<div class="dashboard">
|
|
<header>
|
|
<h1>Dashboard</h1>
|
|
<div class="user-menu">
|
|
<span>{{ authStore.currentUser?.name }}</span>
|
|
<button @click="handleLogout">Logout</button>
|
|
</div>
|
|
</header>
|
|
|
|
<main>
|
|
<p>Welcome back, {{ authStore.currentUser?.name }}!</p>
|
|
<p>Email: {{ authStore.currentUser?.email }}</p>
|
|
</main>
|
|
</div>
|
|
</template>
|
|
```
|
|
|
|
## 📋 Auth Store API Reference
|
|
|
|
```typescript
|
|
const authStore = useAuthStore();
|
|
|
|
// State
|
|
authStore.user // User object or null
|
|
authStore.token // Auth token or null
|
|
authStore.loading // Boolean: loading state
|
|
authStore.error // String: error message or null
|
|
|
|
// Getters
|
|
authStore.isAuthenticated // Boolean: is user logged in?
|
|
authStore.currentUser // User object or null
|
|
|
|
// Actions
|
|
await authStore.login({ email, password, remember }) // Returns boolean
|
|
await authStore.logout() // Returns void
|
|
await authStore.checkAuth() // Returns boolean
|
|
await authStore.fetchUser() // Returns void
|
|
authStore.clearError() // Returns void
|
|
authStore.setUser(userData) // Returns void
|
|
```
|
|
|
|
## ✨ Key Features
|
|
|
|
- ✅ **Auto-persistence**: Auth state saved to localStorage
|
|
- ✅ **CSRF Protection**: Automatically handled
|
|
- ✅ **Error Handling**: Built-in error messages
|
|
- ✅ **Loading States**: Track async operations
|
|
- ✅ **TypeScript**: Full type safety
|
|
- ✅ **Inertia Compatible**: Works with your existing setup
|
|
|
|
## 🐛 Troubleshooting
|
|
|
|
### Issue: User not staying logged in
|
|
**Solution**: Make sure your Laravel API returns the user object on the `/api/auth/user` endpoint
|
|
|
|
### Issue: CSRF token mismatch
|
|
**Solution**: Your existing `resources/js/lib/http.ts` handles this automatically
|
|
|
|
### Issue: Redirect not working
|
|
**Solution**: Ensure you're using `router.get()` from `@inertiajs/vue3`
|
|
|
|
## 📚 Next Steps
|
|
|
|
1. Create your Laravel API endpoints (see examples above)
|
|
2. Update your login page component
|
|
3. Add `useAuthGuard()` to protected pages
|
|
4. Test the authentication flow
|
|
|
|
For detailed documentation, see `AUTH_SETUP.md`
|