feat(01-02): wire OIDC middleware, /api/me route, and authenticated PWA shell
- 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
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* 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>
|
||||
}
|
||||
Reference in New Issue
Block a user