- src/auth/middleware.ts: re-exports oidcAuthMiddleware, processOAuthCallback,
getAuth from @hono/oidc-auth; documents required env vars and AUTH-02
refresh-token rotation (no iframe, D-12)
- src/routes/me.ts: GET / calls getAuth → upsertUser(iss, sub, email) →
returns { user: { id, displayName, color } }; identity keyed on iss+sub
- src/index.ts: /callback registered before oidcAuthMiddleware; /api/*
guarded; /health remains unauthenticated; /api/me mounted
- apps/pwa/src/api/client.ts: typed fetchMe() with credentials: 'include'
- apps/pwa/src/App.tsx: useQuery(['me'], fetchMe); renders member name and
color swatch; retains /health stack indicator from Plan 01
- tsc --noEmit: clean; all tests pass
35 lines
924 B
TypeScript
35 lines
924 B
TypeScript
/**
|
|
* Typed API client for the FamilySync backend.
|
|
*
|
|
* credentials: 'include' is required so the OIDC session cookie is sent with
|
|
* every cross-origin request (Vite dev proxy routes to :3000; production is
|
|
* same-origin via Pangolin).
|
|
*
|
|
* 401 responses mean the session has expired — the browser will follow the
|
|
* 302 redirect to Authelia on the next API call automatically (full-page nav).
|
|
*/
|
|
|
|
export interface MeUser {
|
|
id: number
|
|
displayName: string | null
|
|
color: string
|
|
}
|
|
|
|
export interface MeResponse {
|
|
user: MeUser
|
|
}
|
|
|
|
export async function fetchMe(): Promise<MeResponse> {
|
|
const res = await fetch('/api/me', {
|
|
credentials: 'include',
|
|
})
|
|
|
|
if (!res.ok) {
|
|
// 302 → browser follows redirect to Authelia automatically.
|
|
// For 4xx/5xx, throw so React Query can surface the error.
|
|
throw new Error(`GET /api/me failed: ${res.status}`)
|
|
}
|
|
|
|
return res.json() as Promise<MeResponse>
|
|
}
|