diff --git a/service/src/auth/routes.rs b/service/src/auth/routes.rs index 895461d..e794d09 100644 --- a/service/src/auth/routes.rs +++ b/service/src/auth/routes.rs @@ -340,6 +340,40 @@ async fn me(auth: JwtAuth) -> HttpResponse { HttpResponse::Ok().json(auth) } +#[get("/check-session")] +async fn check_session(req: HttpRequest) -> HttpResponse { + // If there is a access_token cookie, check if it is valid + let has_session = match req.cookie("access_token") { + Some(cookie) => { + let access_token = cookie.value().to_string(); + let public_key = env::var("ACCESS_TOKEN_PUBLIC_KEY") + .expect("ACCESS_TOKEN_PUBLIC_KEY must be set"); + match verify_token(&access_token, &public_key) { + Ok(_) => true, + Err(_) => false + } + }, + None => false + }; + if !has_session { + // If there is a refresh_token cookie, check if it is valid + match req.cookie("refresh_token") { + Some(cookie) => { + let refresh_token = cookie.value().to_string(); + let public_key = env::var("REFRESH_TOKEN_PUBLIC_KEY") + .expect("REFRESH_TOKEN_PUBLIC_KEY must be set"); + match verify_token(&refresh_token, &public_key) { + Ok(_) => return HttpResponse::Ok().json(true), + Err(_) => return HttpResponse::Ok().json(false) + }; + }, + None => return HttpResponse::Ok().json(false) + }; + } else { + return HttpResponse::Ok().json(true) + } +} + #[get("/roles")] async fn roles() -> HttpResponse { HttpResponse::Ok().json(vec!["admin", "user"]) @@ -363,5 +397,6 @@ pub fn init_routes(config: &mut web::ServiceConfig) { .service(logout) .service(me) .service(roles) + .service(check_session) ); } \ No newline at end of file diff --git a/ui/src/api/auth.ts b/ui/src/api/auth.ts index 7831fad..389cc32 100644 --- a/ui/src/api/auth.ts +++ b/ui/src/api/auth.ts @@ -42,6 +42,15 @@ export async function me(): Promise { } } +export async function hasSession(): Promise { + const response = await getRequest('auth/check-session'); + if (response?.status === 200) { + return response?.json(); + } else { + return false; + } +} + /** * Refreshes the logged_in cookie every interval. By default, the interval is 14 minutes. * @param interval diff --git a/ui/src/components/Header/HeaderModal.tsx b/ui/src/components/Header/HeaderModal.tsx index 83adedd..4510353 100644 --- a/ui/src/components/Header/HeaderModal.tsx +++ b/ui/src/components/Header/HeaderModal.tsx @@ -1,6 +1,6 @@ 'use client'; -import { login, register, refreshLoggedIn } from '@/api/auth'; +import { login, register } from '@/api/auth'; import { User } from '@/api/auth.types'; import { Modal, @@ -146,7 +146,6 @@ export function HeaderModal({ type, toggle, setUser, setRefreshId }: HeaderModal const loginResponse = await login(values.email, values.password); if (loginResponse) { setUser(loginResponse.user); - setRefreshId(refreshLoggedIn()); onClose(); notifications.update({ id, @@ -222,7 +221,6 @@ export function HeaderModal({ type, toggle, setUser, setRefreshId }: HeaderModal const response = await login(values.email, values.password); if (response) { setUser(response.user); - setRefreshId(refreshLoggedIn()); onClose(); } else { notifications.show({ diff --git a/ui/src/components/Header/index.tsx b/ui/src/components/Header/index.tsx index 91d6624..a9821b4 100644 --- a/ui/src/components/Header/index.tsx +++ b/ui/src/components/Header/index.tsx @@ -6,7 +6,7 @@ import './header.css'; import { Avatar, Button, Card, Center, FileButton, Grid, Group, Menu, Text, UnstyledButton } from '@mantine/core'; import Cookies from 'js-cookie'; import { useEffect, useState } from 'react'; -import { logout, refresh, refreshLoggedIn } from '@/api/auth'; +import { hasSession, logout, refresh, refreshLoggedIn } from '@/api/auth'; import { useToggle } from '@mantine/hooks'; import { HeaderModal } from './HeaderModal'; import { HeaderItem, headerItems } from './headerItems'; @@ -14,6 +14,7 @@ import { userState } from '@/state/auth'; import { useRecoilState } from 'recoil'; import { getPicture, setPicture } from '@/api/users'; import { BsChevronDown } from 'react-icons/bs'; +import { User } from '@/api/auth.types'; export default function Header() { const pathName = usePathname(); @@ -25,23 +26,33 @@ export default function Header() { const router = useRouter(); useEffect(() => { - if (!user || !Cookies.get('logged_in')) { - refresh().then((response) => { + if (!user) { + hasSession().then((response) => { if (response) { - setRefreshId(refreshLoggedIn()); - setUser(response.user); - if (response.user.profile_picture) { - getPicture().then((response) => { - if (response) { - setProfilePicture(response as File); - } - }); - } + refresh().then((response) => { + if (response) { + setUser(response.user); + updateUser(response.user); + } + }); } }); } }, [user]); + function updateUser(user?: User) { + if (!refreshId) { + setRefreshId(refreshLoggedIn()); + } + if (user) { + getPicture().then((response) => { + if (response) { + setProfilePicture(response as File); + } + }); + } + } + return ( <>