v0.1.6: validate the session on open, not mid-map
All checks were successful
build-apk / build (push) Successful in 38m15s

A stale/expired token doesn't 401 — /api/User returns an empty body, so
getUserDetail() resolved to undefined without throwing and the launch probe set
signedIn anyway. The dead session then only surfaced when the map/kiosk calls
ran. Now the launch check requires real user data (PersonalPhone/Email); if it's
missing it clears the token and shows the login screen at open.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Hank 2026-07-13 10:46:04 -07:00
parent 7212badd2d
commit 65fbd86644
2 changed files with 16 additions and 6 deletions

View file

@ -3,14 +3,14 @@
"name": "BigBrainParking", "name": "BigBrainParking",
"slug": "bigbrainparking", "slug": "bigbrainparking",
"scheme": "bigbrainparking", "scheme": "bigbrainparking",
"version": "0.1.5", "version": "0.1.6",
"orientation": "portrait", "orientation": "portrait",
"userInterfaceStyle": "automatic", "userInterfaceStyle": "automatic",
"newArchEnabled": true, "newArchEnabled": true,
"icon": "./assets/icon.png", "icon": "./assets/icon.png",
"android": { "android": {
"package": "top.mowden.bigbrainparking", "package": "top.mowden.bigbrainparking",
"versionCode": 5, "versionCode": 6,
"edgeToEdgeEnabled": true, "edgeToEdgeEnabled": true,
"adaptiveIcon": { "adaptiveIcon": {
"foregroundImage": "./assets/adaptive-icon.png", "foregroundImage": "./assets/adaptive-icon.png",

View file

@ -37,18 +37,28 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
}; };
}, []); }, []);
// On launch: bootstrap (seeds SessionId + feature flags) and probe for an // On launch: bootstrap (seeds SessionId + feature flags), then verify any
// existing token by attempting an authenticated read. // stored token BEFORE showing the app. A stale/expired token doesn't 401 —
// /api/User just returns an empty body, so getUserDetail() resolves to
// undefined without throwing. Require real user data to count as signed in,
// and clear the dead token otherwise, so an expired session lands on the
// login screen at open instead of failing later on the map.
useEffect(() => { useEffect(() => {
(async () => { (async () => {
try { try {
const v = await ps.getApplicationValidity(); const v = await ps.getApplicationValidity();
setValidity(v); setValidity(v);
const existing = await ps.tokens.getAuthToken(); const existing = await ps.tokens.getAuthToken();
if (existing) { if (!existing) {
await ps.getUserDetail(); // 401 throws -> treated as signed out setStatus('signedOut');
return;
}
const user = await ps.getUserDetail().catch(() => null);
const valid = !!(user && (user.PersonalPhone || user.PersonalEmailAddress));
if (valid) {
setStatus('signedIn'); setStatus('signedIn');
} else { } else {
await ps.logoutLocal(); // drop the dead token so the login screen is clean
setStatus('signedOut'); setStatus('signedOut');
} }
} catch { } catch {