mirror of
https://github.com/lordmathis/lemma.git
synced 2025-11-05 15:44:21 +00:00
Implement cookie auth on frontend
This commit is contained in:
@@ -19,16 +19,10 @@ export const AuthProvider = ({ children }) => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const initializeAuth = async () => {
|
const initializeAuth = async () => {
|
||||||
try {
|
try {
|
||||||
const storedToken = localStorage.getItem('accessToken');
|
const userData = await authApi.getCurrentUser();
|
||||||
if (storedToken) {
|
setUser(userData);
|
||||||
authApi.setAuthToken(storedToken);
|
|
||||||
const userData = await authApi.getCurrentUser();
|
|
||||||
setUser(userData);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to initialize auth:', error);
|
console.error('Failed to initialize auth:', error);
|
||||||
localStorage.removeItem('accessToken');
|
|
||||||
authApi.clearAuthToken();
|
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
setInitialized(true);
|
setInitialized(true);
|
||||||
@@ -40,12 +34,7 @@ export const AuthProvider = ({ children }) => {
|
|||||||
|
|
||||||
const login = useCallback(async (email, password) => {
|
const login = useCallback(async (email, password) => {
|
||||||
try {
|
try {
|
||||||
const { accessToken, user: userData } = await authApi.login(
|
const { user: userData } = await authApi.login(email, password);
|
||||||
email,
|
|
||||||
password
|
|
||||||
);
|
|
||||||
localStorage.setItem('accessToken', accessToken);
|
|
||||||
authApi.setAuthToken(accessToken);
|
|
||||||
setUser(userData);
|
setUser(userData);
|
||||||
notifications.show({
|
notifications.show({
|
||||||
title: 'Success',
|
title: 'Success',
|
||||||
@@ -70,18 +59,17 @@ export const AuthProvider = ({ children }) => {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Logout failed:', error);
|
console.error('Logout failed:', error);
|
||||||
} finally {
|
} finally {
|
||||||
localStorage.removeItem('accessToken');
|
|
||||||
authApi.clearAuthToken();
|
|
||||||
setUser(null);
|
setUser(null);
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const refreshToken = useCallback(async () => {
|
const refreshToken = useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
const { accessToken } = await authApi.refreshToken();
|
const success = await authApi.refreshToken();
|
||||||
localStorage.setItem('accessToken', accessToken);
|
if (!success) {
|
||||||
authApi.setAuthToken(accessToken);
|
await logout();
|
||||||
return true;
|
}
|
||||||
|
return success;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Token refresh failed:', error);
|
console.error('Token refresh failed:', error);
|
||||||
await logout();
|
await logout();
|
||||||
|
|||||||
@@ -1,40 +1,32 @@
|
|||||||
import { API_BASE_URL } from '../utils/constants';
|
import { API_BASE_URL } from '../utils/constants';
|
||||||
|
|
||||||
let authToken = null;
|
|
||||||
|
|
||||||
export const setAuthToken = (token) => {
|
|
||||||
authToken = token;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const clearAuthToken = () => {
|
|
||||||
authToken = null;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getAuthHeaders = () => {
|
|
||||||
const headers = {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
};
|
|
||||||
|
|
||||||
if (authToken) {
|
|
||||||
headers['Authorization'] = `Bearer ${authToken}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return headers;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Update the existing apiCall function to include auth headers
|
|
||||||
export const apiCall = async (url, options = {}) => {
|
export const apiCall = async (url, options = {}) => {
|
||||||
try {
|
try {
|
||||||
const headers = {
|
const headers = {
|
||||||
...getAuthHeaders(),
|
'Content-Type': 'application/json',
|
||||||
...options.headers,
|
...options.headers,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (options.method && options.method !== 'GET') {
|
||||||
|
const csrfToken = document.cookie
|
||||||
|
.split('; ')
|
||||||
|
.find((row) => row.startsWith('csrf_token='))
|
||||||
|
?.split('=')[1];
|
||||||
|
if (csrfToken) {
|
||||||
|
headers['X-CSRF-Token'] = csrfToken;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const response = await fetch(url, {
|
const response = await fetch(url, {
|
||||||
...options,
|
...options,
|
||||||
headers,
|
headers,
|
||||||
|
credentials: 'include',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (response.status === 429) {
|
||||||
|
throw new Error('Rate limit exceeded');
|
||||||
|
}
|
||||||
|
|
||||||
// Handle 401 responses
|
// Handle 401 responses
|
||||||
if (response.status === 401) {
|
if (response.status === 401) {
|
||||||
const isRefreshEndpoint = url.endsWith('/auth/refresh');
|
const isRefreshEndpoint = url.endsWith('/auth/refresh');
|
||||||
@@ -42,13 +34,14 @@ export const apiCall = async (url, options = {}) => {
|
|||||||
// Attempt token refresh and retry the request
|
// Attempt token refresh and retry the request
|
||||||
const refreshSuccess = await refreshToken();
|
const refreshSuccess = await refreshToken();
|
||||||
if (refreshSuccess) {
|
if (refreshSuccess) {
|
||||||
// Retry the original request with the new token
|
// Retry the original request
|
||||||
return apiCall(url, options);
|
return apiCall(url, options);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw new Error('Authentication failed');
|
throw new Error('Authentication failed');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle other error responses
|
||||||
if (!response.ok && response.status !== 204) {
|
if (!response.ok && response.status !== 204) {
|
||||||
const errorData = await response.json().catch(() => null);
|
const errorData = await response.json().catch(() => null);
|
||||||
throw new Error(
|
throw new Error(
|
||||||
@@ -56,6 +49,7 @@ export const apiCall = async (url, options = {}) => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return null for 204 responses
|
||||||
if (response.status === 204) {
|
if (response.status === 204) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -73,26 +67,29 @@ export const login = async (email, password) => {
|
|||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: JSON.stringify({ email, password }),
|
body: JSON.stringify({ email, password }),
|
||||||
});
|
});
|
||||||
return response.json();
|
|
||||||
|
const data = await response.json();
|
||||||
|
// No need to store tokens as they're in cookies now
|
||||||
|
return data;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const logout = async () => {
|
export const logout = async () => {
|
||||||
const sessionId = localStorage.getItem('sessionId');
|
|
||||||
await apiCall(`${API_BASE_URL}/auth/logout`, {
|
await apiCall(`${API_BASE_URL}/auth/logout`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
|
||||||
'X-Session-ID': sessionId,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const refreshToken = async () => {
|
export const refreshToken = async () => {
|
||||||
const refreshToken = localStorage.getItem('refreshToken');
|
try {
|
||||||
const response = await apiCall(`${API_BASE_URL}/auth/refresh`, {
|
const response = await apiCall(`${API_BASE_URL}/auth/refresh`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: JSON.stringify({ refreshToken }),
|
});
|
||||||
});
|
return response.status === 200;
|
||||||
return response.json();
|
} catch (error) {
|
||||||
|
console.error('Token refresh failed:', error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getCurrentUser = async () => {
|
export const getCurrentUser = async () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user