diff options
| author | nsfisis <nsfisis@gmail.com> | 2025-03-21 13:10:56 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2025-03-21 13:10:56 +0900 |
| commit | 589d2355910e8fc63eabecad631b16b3d3d6a492 (patch) | |
| tree | 9012e7a1bc8396227c3b018d0535f937aac2a0d6 | |
| parent | a75f9fa78897de7317fe336e68db7a255899ae33 (diff) | |
| download | phperkaigi-2025-albatross-589d2355910e8fc63eabecad631b16b3d3d6a492.tar.gz phperkaigi-2025-albatross-589d2355910e8fc63eabecad631b16b3d3d6a492.tar.zst phperkaigi-2025-albatross-589d2355910e8fc63eabecad631b16b3d3d6a492.zip | |
fix(frontend): refresh jwt if expired
| -rw-r--r-- | frontend/app/.server/auth.ts | 32 | ||||
| -rw-r--r-- | frontend/app/components/NavigateLink.tsx | 2 |
2 files changed, 23 insertions, 11 deletions
diff --git a/frontend/app/.server/auth.ts b/frontend/app/.server/auth.ts index 81ceadf..d56c193 100644 --- a/frontend/app/.server/auth.ts +++ b/frontend/app/.server/auth.ts @@ -1,4 +1,4 @@ -import { jwtDecode } from "jwt-decode"; +import { jwtDecode, type JwtPayload } from "jwt-decode"; import { redirect } from "react-router"; import { Authenticator } from "remix-auth"; import { FormStrategy } from "remix-auth-form"; @@ -58,26 +58,38 @@ export async function logout(request: Request): Promise<never> { }); } -export async function ensureUserLoggedIn( +async function getCurrentValidSession( request: Request, -): Promise<{ user: User; token: string }> { +): Promise<{ user: User; token: string } | null> { const session = await sessionStorage.getSession( request.headers.get("cookie"), ); const token = session.get("user"); if (!token) { - throw redirect("/login"); + return null; + } + const user = jwtDecode<User & JwtPayload>(token); + const exp = user.exp; + if (exp != null && new Date((exp - 3600) * 1000) < new Date()) { + // If the token will expire in less than an hour, refresh it. + return null; } - const user = jwtDecode<User>(token); return { user, token }; } +export async function ensureUserLoggedIn( + request: Request, +): Promise<{ user: User; token: string }> { + const session = await getCurrentValidSession(request); + if (!session) { + throw redirect("/login"); + } + return session; +} + export async function ensureUserNotLoggedIn(request: Request): Promise<null> { - const session = await sessionStorage.getSession( - request.headers.get("cookie"), - ); - const token = session.get("user"); - if (token) { + const session = await getCurrentValidSession(request); + if (session) { throw redirect("/dashboard"); } return null; diff --git a/frontend/app/components/NavigateLink.tsx b/frontend/app/components/NavigateLink.tsx index 16dbf64..c4ee7aa 100644 --- a/frontend/app/components/NavigateLink.tsx +++ b/frontend/app/components/NavigateLink.tsx @@ -4,7 +4,7 @@ export default function NavigateLink(props: LinkProps) { return ( <Link {...props} - className="text-lg text-white bg-sky-600 px-4 py-2 rounded-sm transition duration-300 hover:bg-sky-500 focus:ring-3 focus:ring-sky-400 focus:outline-hidden" + className="text-lg text-white bg-sky-600 px-4 py-2 border-2 border-sky-50 rounded-sm transition duration-300 hover:bg-sky-500 focus:ring-3 focus:ring-sky-400 focus:outline-hidden" /> ); } |
