improved AuthProvider

This commit is contained in:
slawk0
2024-12-30 19:18:54 +01:00
parent a7866a3f3a
commit 0507697d8b
4 changed files with 70 additions and 32 deletions

View File

@@ -3,7 +3,7 @@ import {
createBrowserRouter, createBrowserRouter,
Navigate, Navigate,
} from 'react-router-dom'; } from 'react-router-dom';
import { useState } from 'react'; import { useEffect, useState } from 'react';
import Chat from './pages/Chat.tsx'; import Chat from './pages/Chat.tsx';
import Login from './pages/Login.tsx'; import Login from './pages/Login.tsx';
import Signup from './pages/Signup.tsx'; import Signup from './pages/Signup.tsx';
@@ -11,7 +11,9 @@ import Settings from './pages/Settings.tsx';
import Lost from './pages/404.tsx'; import Lost from './pages/404.tsx';
import { AuthContext } from './utils/AuthProvider.tsx'; import { AuthContext } from './utils/AuthProvider.tsx';
import ProtectedRoutes from './utils/ProtectedRoutes.tsx'; import ProtectedRoutes from './utils/ProtectedRoutes.tsx';
import PublicRoute from '@/utils/PublicRoute.tsx';
import axios from 'axios'; import axios from 'axios';
import Cookies from 'js-cookie';
export const axiosClient = axios.create({ export const axiosClient = axios.create({
baseURL: import.meta.env.VITE_BASE_URL, baseURL: import.meta.env.VITE_BASE_URL,
}); });
@@ -34,12 +36,17 @@ const router = createBrowserRouter([
], ],
}, },
{ {
path: '/login', element: <PublicRoute />,
element: <Login />, children: [
}, {
{ path: '/login',
path: '/signup', element: <Login />,
element: <Signup />, },
{
path: '/signup',
element: <Signup />,
},
],
}, },
{ {
path: '*', path: '*',
@@ -48,12 +55,38 @@ const router = createBrowserRouter([
]); ]);
function App() { function App() {
const [authorized, setAuthorized] = useState<boolean | null>(null); const [authorized, setAuthorized] = useState(false);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
async function validateToken() {
const token = Cookies.get('token');
if (!token) {
setAuthorized(false);
setIsLoading(false);
return;
}
try {
await axiosClient.get('/api/auth/validate', {
withCredentials: true,
});
setAuthorized(true);
} catch (e) {
setAuthorized(false);
console.log('Failed to validate token: ', e);
} finally {
setIsLoading(false);
}
}
validateToken();
}, []);
return ( return (
<AuthContext.Provider value={{ authorized, setAuthorized }}> <AuthContext.Provider value={{ authorized, isLoading, setAuthorized }}>
<RouterProvider router={router} /> <RouterProvider router={router} />
</AuthContext.Provider> </AuthContext.Provider>
); );
} }
export default App; export default App;

View File

@@ -1,10 +1,13 @@
import { createContext } from 'react'; import { createContext } from 'react';
type AuthContextType = { type AuthContextType = {
authorized: boolean | null; authorized: boolean;
isLoading: boolean;
setAuthorized: (value: boolean) => void; setAuthorized: (value: boolean) => void;
}; };
export const AuthContext = createContext<AuthContextType>({ export const AuthContext = createContext<AuthContextType>({
authorized: null, authorized: false,
isLoading: true,
setAuthorized: () => {}, setAuthorized: () => {},
}); });

View File

@@ -1,6 +1,5 @@
import { Navigate, Outlet } from 'react-router-dom'; import { Navigate, Outlet } from 'react-router-dom';
import { useState, useEffect, useContext } from 'react'; import { useState, useEffect, useContext } from 'react';
import Cookie from 'js-cookie';
import { AuthContext } from './AuthProvider.tsx'; import { AuthContext } from './AuthProvider.tsx';
import LoadingScreen from '../components/LoadingScreen.tsx'; import LoadingScreen from '../components/LoadingScreen.tsx';
import { axiosClient } from '../App.tsx'; import { axiosClient } from '../App.tsx';
@@ -11,37 +10,24 @@ export type UsernameType = {
}; };
function ProtectedRoutes() { function ProtectedRoutes() {
const { authorized, setAuthorized } = useContext(AuthContext); const { authorized, isLoading } = useContext(AuthContext);
const [user, setUser] = useState<UsernameType>({ const [user, setUser] = useState<UsernameType>({
username: null, username: null,
user_id: null, user_id: null,
}); });
useEffect(() => { useEffect(() => {
function validateToken() { if (authorized) {
const token = Cookie.get('token');
if (!token) {
setAuthorized(false);
return;
}
axiosClient axiosClient
.get('/api/auth/validate', { withCredentials: true }) .get('/api/auth/validate', { withCredentials: true })
.then(async (res) => { .then((res) => {
setUser(res.data); setUser(res.data);
console.log('User: ', res.data);
setAuthorized(true);
}) })
.catch((err) => { .catch(console.error);
setAuthorized(false);
console.log(err);
console.log('Unauthorized');
});
} }
validateToken(); }, [authorized]);
}, [setAuthorized]);
if (authorized === null) { if (isLoading) {
return <LoadingScreen />; return <LoadingScreen />;
} }

View File

@@ -0,0 +1,16 @@
import { Navigate, Outlet } from 'react-router-dom';
import { useContext } from 'react';
import { AuthContext } from './AuthProvider';
import LoadingScreen from '../components/LoadingScreen';
function PublicRoute() {
const { authorized, isLoading } = useContext(AuthContext);
if (isLoading) {
return <LoadingScreen />;
}
return authorized ? <Navigate to="/chat" replace /> : <Outlet />;
}
export default PublicRoute;