/** * API Client Wrapper * Centralized API communication with auth handling */ const api = { /** * Get the auth token from localStorage */ getToken() { return localStorage.getItem('access_token'); }, /** * Set the auth token */ setToken(token) { localStorage.setItem('access_token', token); }, /** * Clear the auth token */ clearToken() { localStorage.removeItem('access_token'); }, /** * Check if user is authenticated (token or Authelia) */ isAuthenticated() { return !!this.getToken() || this._autheliaAuth; }, /** * Check authentication - works with both JWT and Authelia * Call this on page load to verify auth status */ async checkAuth() { // Try to get current user - works with Authelia headers or JWT const response = await fetch('/api/auth/me', { headers: this.getToken() ? { 'Authorization': `Bearer ${this.getToken()}` } : {} }); if (response.ok) { this._autheliaAuth = true; return await response.json(); } this._autheliaAuth = false; return null; }, /** * Redirect to login if not authenticated * Returns user object if authenticated, null otherwise */ async requireAuth() { const user = await this.checkAuth(); if (!user) { window.location.href = '/login'; return null; } return user; }, /** * Make an API request */ async request(method, url, data = null) { const options = { method, headers: {} }; const token = this.getToken(); if (token) { options.headers['Authorization'] = `Bearer ${token}`; } if (data) { options.headers['Content-Type'] = 'application/json'; options.body = JSON.stringify(data); } const response = await fetch(url, options); // Handle 401 - redirect to login if (response.status === 401) { this.clearToken(); window.location.href = '/login'; return null; } return response; }, /** * GET request */ async get(url) { return this.request('GET', url); }, /** * POST request */ async post(url, data) { return this.request('POST', url, data); }, /** * PUT request */ async put(url, data) { return this.request('PUT', url, data); }, /** * PATCH request */ async patch(url, data) { return this.request('PATCH', url, data); }, /** * DELETE request */ async delete(url) { return this.request('DELETE', url); }, /** * Get current user info */ async getCurrentUser() { const response = await this.get('/api/auth/me'); if (response && response.ok) { return await response.json(); } return null; }, /** * Login */ async login(email, password) { const response = await fetch('/api/auth/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email, password }) }); if (response.ok) { const data = await response.json(); this.setToken(data.access_token); return { success: true }; } const error = await response.json(); return { success: false, error: error.detail || 'Login failed' }; }, /** * Register */ async register(email, password, name) { const response = await fetch('/api/auth/register', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email, password, name }) }); if (response.ok) { const data = await response.json(); this.setToken(data.access_token); return { success: true }; } const error = await response.json(); return { success: false, error: error.detail || 'Registration failed' }; }, /** * Logout */ async logout() { await this.post('/api/auth/logout', {}); this.clearToken(); window.location.href = '/login'; } }; // Make globally available window.api = api;