Skip to content

Commit 9ad9ec8

Browse files
committed
add a lock around auth checking for AuthGuard
1 parent f729b90 commit 9ad9ec8

File tree

2 files changed

+85
-66
lines changed

2 files changed

+85
-66
lines changed

src/ui/components/AuthContext/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ export const AuthProvider: React.FC<AuthProviderProps> = ({ children }) => {
104104
});
105105
const api = useApi('core');
106106
const result = await api.get(checkRoute);
107-
setCachedResponse('core', checkRoute, result.data);
107+
await setCachedResponse('core', checkRoute, result.data);
108108
setIsLoggedIn(true);
109109
}
110110
})
@@ -192,7 +192,7 @@ export const AuthProvider: React.FC<AuthProviderProps> = ({ children }) => {
192192
instance.setActiveAccount(accountsLocal[0]);
193193
const api = useApi('core');
194194
const result = await api.get(checkRoute);
195-
setCachedResponse('core', checkRoute, result.data);
195+
await setCachedResponse('core', checkRoute, result.data);
196196
setIsLoggedIn(true);
197197
} else {
198198
await instance.loginRedirect({

src/ui/components/AuthGuard/index.tsx

Lines changed: 83 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -23,32 +23,46 @@ export type ResourceDefinition = {
2323
const getAuthCacheKey = (service: ValidService, route: string) =>
2424
`${CACHE_KEY_PREFIX}${service}_${route}`;
2525

26-
export const getCachedResponse = (service: ValidService, route: string): CacheData | null => {
27-
const cached = sessionStorage.getItem(getAuthCacheKey(service, route));
28-
if (!cached) return null;
26+
export const getCachedResponse = async (
27+
service: ValidService,
28+
route: string
29+
): Promise<CacheData | null> => {
30+
const cacheKey = getAuthCacheKey(service, route);
31+
const item = (await navigator.locks.request(
32+
`lock_${cacheKey}`,
33+
{ mode: 'shared' },
34+
async (lock) => {
35+
const cached = sessionStorage.getItem(getAuthCacheKey(service, route));
36+
if (!cached) return null;
2937

30-
try {
31-
const data = JSON.parse(cached) as CacheData;
32-
const now = Date.now();
38+
try {
39+
const data = JSON.parse(cached) as CacheData;
40+
const now = Date.now();
3341

34-
if (now - data.timestamp <= CACHE_DURATION) {
35-
return data;
42+
if (now - data.timestamp <= CACHE_DURATION) {
43+
return data;
44+
}
45+
// Clear expired cache
46+
sessionStorage.removeItem(getAuthCacheKey(service, route));
47+
} catch (e) {
48+
console.error('Error parsing auth cache:', e);
49+
sessionStorage.removeItem(getAuthCacheKey(service, route));
50+
}
51+
return null;
3652
}
37-
// Clear expired cache
38-
sessionStorage.removeItem(getAuthCacheKey(service, route));
39-
} catch (e) {
40-
console.error('Error parsing auth cache:', e);
41-
sessionStorage.removeItem(getAuthCacheKey(service, route));
42-
}
43-
return null;
53+
)) as CacheData | null;
54+
return item;
4455
};
4556

46-
export const setCachedResponse = (service: ValidService, route: string, data: any) => {
57+
export const setCachedResponse = async (service: ValidService, route: string, data: any) => {
4758
const cacheData: CacheData = {
4859
data,
4960
timestamp: Date.now(),
5061
};
51-
sessionStorage.setItem(getAuthCacheKey(service, route), JSON.stringify(cacheData));
62+
const cacheKey = getAuthCacheKey(service, route);
63+
await navigator.locks.request(`lock_${cacheKey}`, { mode: 'exclusive' }, async (lock) => {
64+
sessionStorage.setItem(cacheKey, JSON.stringify(cacheData));
65+
});
5266
};
5367

5468
// Function to clear auth cache for all services
@@ -79,59 +93,64 @@ export const AuthGuard: React.FC<
7993

8094
useEffect(() => {
8195
async function getAuth() {
82-
try {
83-
if (!authCheckRoute) {
84-
setIsAuthenticated(true);
85-
return;
86-
}
87-
if (validRoles.length === 0) {
88-
setIsAuthenticated(true);
89-
return;
90-
}
96+
await navigator.locks.request(
97+
`lock_authGuard_loader`,
98+
{ mode: 'exclusive' },
99+
async (lock) => {
100+
try {
101+
if (!authCheckRoute) {
102+
setIsAuthenticated(true);
103+
return;
104+
}
105+
if (validRoles.length === 0) {
106+
setIsAuthenticated(true);
107+
return;
108+
}
91109

92-
// Check for cached response first
93-
setIsLoading(true);
94-
const cachedData = getCachedResponse(service, authCheckRoute);
95-
if (cachedData !== null) {
96-
const userRoles = cachedData.data.roles;
97-
let authenticated = false;
98-
for (const item of userRoles) {
99-
if (validRoles.indexOf(item) !== -1) {
100-
authenticated = true;
101-
break;
110+
// Check for cached response first
111+
setIsLoading(true);
112+
const cachedData = await getCachedResponse(service, authCheckRoute);
113+
if (cachedData !== null) {
114+
const userRoles = cachedData.data.roles;
115+
let authenticated = false;
116+
for (const item of userRoles) {
117+
if (validRoles.indexOf(item) !== -1) {
118+
authenticated = true;
119+
break;
120+
}
121+
}
122+
setUsername(cachedData.data.username);
123+
setRoles(cachedData.data.roles);
124+
setIsAuthenticated(authenticated);
125+
setIsLoading(false);
126+
return;
102127
}
103-
}
104-
setUsername(cachedData.data.username);
105-
setRoles(cachedData.data.roles);
106-
setIsAuthenticated(authenticated);
107-
setIsLoading(false);
108-
return;
109-
}
110128

111-
// If no cache, make the API call
112-
const result = await api.get(authCheckRoute);
113-
// Cache just the response data
114-
setCachedResponse(service, authCheckRoute, result.data);
115-
116-
const userRoles = result.data.roles;
117-
let authenticated = false;
118-
for (const item of userRoles) {
119-
if (validRoles.indexOf(item) !== -1) {
120-
authenticated = true;
121-
break;
129+
// If no cache, make the API call
130+
const result = await api.get(authCheckRoute);
131+
// Cache just the response data
132+
await setCachedResponse(service, authCheckRoute, result.data);
133+
134+
const userRoles = result.data.roles;
135+
let authenticated = false;
136+
for (const item of userRoles) {
137+
if (validRoles.indexOf(item) !== -1) {
138+
authenticated = true;
139+
break;
140+
}
141+
}
142+
setIsAuthenticated(authenticated);
143+
setRoles(result.data.roles);
144+
setUsername(result.data.username);
145+
setIsLoading(false);
146+
} catch (e) {
147+
setIsAuthenticated(false);
148+
setIsLoading(false);
149+
console.error(e);
122150
}
123151
}
124-
setIsAuthenticated(authenticated);
125-
setRoles(result.data.roles);
126-
setUsername(result.data.username);
127-
setIsLoading(false);
128-
} catch (e) {
129-
setIsAuthenticated(false);
130-
setIsLoading(false);
131-
console.error(e);
132-
}
152+
);
133153
}
134-
135154
getAuth();
136155
}, [baseEndpoint, authCheckRoute, service]);
137156
if (isLoading && loadingSkeleton) {

0 commit comments

Comments
 (0)