From 6dd4d9309c34aebe8ed6426ccf61a55ad07c4a29 Mon Sep 17 00:00:00 2001 From: Christophe Vila Date: Fri, 24 Jul 2026 21:44:19 +0200 Subject: [PATCH] frontend: add session API, credentialed fetch, 401-triggered relogin --- frontend/src/api/client.ts | 16 ++++++++++++++++ frontend/src/types/api.ts | 5 +++++ 2 files changed, 21 insertions(+) diff --git a/frontend/src/api/client.ts b/frontend/src/api/client.ts index e7feb57..c4a96f9 100644 --- a/frontend/src/api/client.ts +++ b/frontend/src/api/client.ts @@ -7,6 +7,7 @@ import type { ProgressionMetric, ProgressionPoint, ReviewQueuePage, + SessionInfo, SyncRun, SyncStatus, WorkoutKind, @@ -17,8 +18,17 @@ const BASE_URL = import.meta.env.VITE_API_BASE_URL ?? "http://localhost:8080"; async function request(path: string, init?: RequestInit): Promise { const res = await fetch(`${BASE_URL}${path}`, { headers: { "Content-Type": "application/json" }, + credentials: "include", ...init, }); + if (res.status === 401 && path !== "/api/session/me") { + // An established session expired mid-use (not the initial "am I logged + // in" check, which LoginGate itself interprets) -- reload so LoginGate + // re-checks and shows the login screen instead of leaving the SPA in a + // half-authenticated state. + window.location.href = "/"; + throw new Error(`${init?.method ?? "GET"} ${path} failed: 401 (session expired)`); + } if (!res.ok) { const body = await res.text(); throw new Error(`${init?.method ?? "GET"} ${path} failed: ${res.status} ${body}`); @@ -28,6 +38,12 @@ async function request(path: string, init?: RequestInit): Promise { } export const api = { + // Session (app login via OIDC -- distinct from the Garmin credential + // login below). No logout()/login() methods: those are plain + // full-page navigations (see LoginGate.tsx), not fetches, since the OIDC + // flow and Keycloak's own logout redirect need real browser navigation. + getSessionInfo: () => request("/api/session/me"), + // Auth login: () => request("/api/auth/login", { method: "POST" }), submitMFA: (code: string) => diff --git a/frontend/src/types/api.ts b/frontend/src/types/api.ts index 23cddb0..348bfa0 100644 --- a/frontend/src/types/api.ts +++ b/frontend/src/types/api.ts @@ -186,6 +186,11 @@ export interface AuthResponse { message: string; } +export interface SessionInfo { + name: string; + email: string; +} + export interface DetailFillProgress { Done: number; Total: number;