Authentication
XetaSuite uses Laravel Sanctum in stateful mode (cookies) for SPA authentication. No API tokens are stored client-side.
Authentication Flow
Section titled “Authentication Flow”sequenceDiagram participant SPA as React SPA participant Laravel as Laravel Backend
SPA->>Laravel: GET /sanctum/csrf-cookie Laravel-->>SPA: Set XSRF-TOKEN cookie SPA->>Laravel: POST /api/v1/auth/login (+ credentials) Laravel-->>SPA: Set session cookie SPA->>Laravel: GET /api/v1/user (with cookies) Laravel-->>SPA: User data + permissionsBackend Configuration
Section titled “Backend Configuration”Sanctum (config/sanctum.php)
Section titled “Sanctum (config/sanctum.php)”'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', 'localhost,localhost:5173,127.0.0.1,xetasuite.test')),CORS (config/cors.php)
Section titled “CORS (config/cors.php)”'paths' => ['api/*', 'sanctum/csrf-cookie'],'allowed_origins' => [env('FRONTEND_URL', 'http://localhost:5173')],'supports_credentials' => true,Frontend Configuration
Section titled “Frontend Configuration”HTTP Client (Axios)
Section titled “HTTP Client (Axios)”const httpClient = axios.create({ baseURL: import.meta.env.VITE_API_URL || '', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', 'X-Requested-With': 'XMLHttpRequest', }, withCredentials: true, // ⚠️ Required for Sanctum withXSRFToken: true, // Auto-include X-XSRF-TOKEN header});Login Implementation
Section titled “Login Implementation”-
Get CSRF cookie
await axios.get('/sanctum/csrf-cookie'); -
Send credentials
await httpClient.post('/api/v1/auth/login', {email: 'admin@xetasuite.test',password: 'password',remember: true}); -
Fetch user
const { data } = await httpClient.get('/api/v1/user');// data contains: user, roles[], permissions[]
Permission Checking
Section titled “Permission Checking”// In React componentsconst { hasPermission, hasRole, hasAnyPermission, hasAnyRole, isOnHeadquarters} = useAuth();
// Check a permissionif (hasPermission('company.create')) { // Show create button}
// Check a roleif (hasRole('admin')) { // Show admin panel}
// Check any of the permissionsif (hasAnyPermission(['company.update', 'company.delete'])) { // Show menu}
// Check any of the rolesif (hasRole(['admin', 'manager'])) { // Show user edit button}
// Check if current user is on headquarters siteif (isOnHeadquarters()) { // User is on headquarters site}Next Steps
Section titled “Next Steps”- Roles & Permissions - Permission system
- Multi-Sites - Per-site permissions