mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-12 22:26:13 +00:00
fix(auth): end the session when a refetch of the account says 401
A failed refetch keeps the last good payload in the query cache, so a session that expired while the app was open still read as signed in: the shell kept its pages, and every save failed with "sign in again". A 401 or 403 now ends the session even with a cached account; a network failure or a 5xx still holds the last known state.
This commit is contained in:
1 parent
a03782f93f
commit
b89599d66a
2 files changed
+31
-4
No files matched your search
@@ -136,6 +136,30 @@ describe("useAuth — last-known state on a non-verdict failure", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("useAuth — a verdict on a refetch", () => {
|
||||
it("ends the session on a 401 although the cache still holds the account", () => {
|
||||
store.set("healthlog-was-authenticated", "1");
|
||||
queryState.data = { id: "u1", username: "someone" };
|
||||
queryState.isError = true;
|
||||
queryState.error = new ApiError("unauthorized", 401);
|
||||
|
||||
const auth = useAuth();
|
||||
expect(auth.isAuthenticated).toBe(false);
|
||||
expect(auth.user).toBeNull();
|
||||
expect(auth.isAuthUnknown).toBe(false);
|
||||
});
|
||||
|
||||
it("keeps the cached account through a network failure on a refetch", () => {
|
||||
queryState.data = { id: "u1", username: "someone" };
|
||||
queryState.isError = true;
|
||||
queryState.error = new TypeError("Failed to fetch");
|
||||
|
||||
const auth = useAuth();
|
||||
expect(auth.isAuthenticated).toBe(true);
|
||||
expect(auth.user).toEqual({ id: "u1", username: "someone" });
|
||||
});
|
||||
});
|
||||
|
||||
describe("session-end marker lifecycle", () => {
|
||||
it("clearCachesForSessionEnd drops the marker so the next cold offline launch lands on the login gate", () => {
|
||||
store.set("healthlog-was-authenticated", "1");
|
||||
|
||||
@@ -536,11 +536,14 @@ export function useAuth() {
|
||||
// /auth/login and wiped every offline cache (data 7→0 entries, pages 1→0
|
||||
// in the audit measurement), making the whole offline story unreachable.
|
||||
const verdictUnknown = query.isError && isAuthVerdictUnknown(query.error);
|
||||
const isAuthenticated =
|
||||
!!query.data || (verdictUnknown && readWasAuthenticated());
|
||||
// A 401/403 on a refetch ends the session although the cache still holds
|
||||
// the last good payload: React Query keeps `data` when a refetch fails.
|
||||
const sessionEnded = query.isError && !verdictUnknown;
|
||||
const user = sessionEnded ? null : (query.data ?? null);
|
||||
const isAuthenticated = !!user || (verdictUnknown && readWasAuthenticated());
|
||||
|
||||
return {
|
||||
user: query.data ?? null,
|
||||
user,
|
||||
isLoading: query.isLoading,
|
||||
isAuthenticated,
|
||||
/**
|
||||
@@ -550,7 +553,7 @@ export function useAuth() {
|
||||
* wipe: a wipe without a 401/403 verdict would destroy the offline
|
||||
* caches on every network blip.
|
||||
*/
|
||||
isAuthUnknown: !query.data && verdictUnknown,
|
||||
isAuthUnknown: !user && verdictUnknown,
|
||||
error: query.error,
|
||||
refetch: query.refetch,
|
||||
};
|
||||
|
||||
Reference in new issue
Block a user