Skip to content

Commit

Permalink
Change token verification
Browse files Browse the repository at this point in the history
  • Loading branch information
Derstilon committed Oct 13, 2023
1 parent fe56e55 commit 581ca68
Showing 1 changed file with 56 additions and 37 deletions.
93 changes: 56 additions & 37 deletions src/services/AuthService.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Backdrop, CircularProgress, Typography } from '@mui/material';
import Keycloak from 'keycloak-js';
import ky, { HTTPError } from 'ky';
import { KyInstance } from 'ky/distribution/types/ky';
Expand Down Expand Up @@ -88,6 +89,8 @@ const Auth = ({ children }: GenericContextProviderProps) => {
setReachInterval(isServerReachable ? 180000 : undefined);
}, [isServerReachable]);

const ignored_messages = ['No token provided'];

const kyRef = useMemo(
() =>
ky.create({
Expand All @@ -114,17 +117,18 @@ const Auth = ({ children }: GenericContextProviderProps) => {
.json()
.then(parseYaptideResponseMessage);

enqueueSnackbar(message, {
variant: 'error'
});
if (!ignored_messages.includes(message))
enqueueSnackbar(message, {
variant: 'error'
});

return Promise.reject(response);
}
}
]
}
}),
[backendUrl, enqueueSnackbar]
[backendUrl, enqueueSnackbar, ignored_messages]
);

const kyIntervalRef = useMemo(
Expand Down Expand Up @@ -171,9 +175,11 @@ const Auth = ({ children }: GenericContextProviderProps) => {
else if (!isServerReachable || !user?.source) setRefreshInterval(undefined);
}, [isServerReachable, user]);

const tokenLogin = useCallback(() => {
const tokenVerification = useCallback(() => {
if (!keycloak.authenticated) return Promise.reject();
const username = keycloak.tokenParsed?.preferred_username;
kyRef

return kyRef
.post(`auth/keycloak`, {
headers: {
Authorization: `Bearer ${keycloak.token}`
Expand All @@ -188,7 +194,10 @@ const Auth = ({ children }: GenericContextProviderProps) => {
source: 'keycloak'
});
})
.catch((_: HTTPError) => {});
.catch((_: HTTPError) => {
setUser(null);
setRefreshInterval(undefined);
});
}, [kyRef]);

useEffect(() => {
Expand All @@ -206,10 +215,22 @@ const Auth = ({ children }: GenericContextProviderProps) => {
? getRefreshDelay(keycloak.tokenParsed.exp * 1000)
: undefined
);
tokenLogin();
tokenVerification();
}
});
}, [tokenLogin]);
}, [tokenVerification]);

const logout = useCallback(() => {
if (user?.source === 'keycloak') keycloak.logout();
kyRef
.delete(`auth/logout`)
.json<YaptideResponse>()
.catch((_: HTTPError) => {})
.finally(() => {
setUser(null);
setRefreshInterval(undefined);
});
}, [kyRef, user?.source]);

const login = useCallback(
(...[username, password]: RequestAuthLogin) => {
Expand All @@ -223,46 +244,41 @@ const Auth = ({ children }: GenericContextProviderProps) => {
setRefreshInterval(getRefreshDelay(accessExp));
enqueueSnackbar('Logged in.', { variant: 'success' });
})
.catch((_: HTTPError) => {});
.catch((_: HTTPError) => {
enqueueSnackbar('Login failed.', { variant: 'error' });
setRefreshInterval(undefined);
logout();
});
},
[enqueueSnackbar, kyRef]
[enqueueSnackbar, kyRef, logout]
);

const logout = useCallback(() => {
if (user?.source === 'keycloak') keycloak.logout();
kyRef
.delete(`auth/logout`)
.json<YaptideResponse>()
.catch((_: HTTPError) => {})
.finally(() => setUser(null));
}, [kyRef, user?.source]);

const tokenRefresh = useCallback(() => {
if (!keycloak.authenticated) {
setKeyCloakInterval(undefined);

return Promise.resolve();
}

return keycloak
.updateToken(300) // 5 minutes in seconds minimum remaining lifetime for token before refresh is allowed
.then(refreshed => {
if (refreshed)
console.log(
`Token refreshed ${keycloak.tokenParsed?.exp} -> ${keycloak.tokenParsed?.exp}`
enqueueSnackbar(
`Token refreshed ${keycloak.tokenParsed?.exp} -> ${keycloak.tokenParsed?.exp}`,
{ variant: 'success' }
);
})
.catch(() => {
console.log('Failed to refresh token');
logout();
});
}, [logout]);
.catch(reason => logout());
}, [enqueueSnackbar, logout]);

useIntervalAsync(tokenRefresh, keycloak.authenticated ? keyCloakInterval : undefined);

const isAuthorized = useMemo(() => user !== null || demoMode, [demoMode, user]);

const refresh = useCallback(async () => {
if (user?.source === 'keycloak') return tokenLogin();
if (demoMode || !isServerReachable) return Promise.resolve(setRefreshInterval(undefined));
if (user?.source === 'keycloak' && isAuthorized) return tokenVerification();

if (demoMode || !isServerReachable) {
setRefreshInterval(undefined);
setUser(null);

return Promise.reject();
}

try {
const { accessExp } = await kyIntervalRef
Expand All @@ -271,10 +287,9 @@ const Auth = ({ children }: GenericContextProviderProps) => {

return setRefreshInterval(getRefreshDelay(accessExp));
} catch (_) {}
}, [demoMode, isServerReachable, kyIntervalRef, tokenLogin, user?.source]);
}, [demoMode, isAuthorized, isServerReachable, kyIntervalRef, tokenVerification, user?.source]);

const authKy = useMemo(() => kyRef, [kyRef]);
const isAuthorized = useMemo(() => user !== null || demoMode, [demoMode, user]);

useEffect(() => {
save(StorageKey.USER, user);
Expand All @@ -295,6 +310,10 @@ const Auth = ({ children }: GenericContextProviderProps) => {
refresh
}}>
{children}
<Backdrop open={Boolean(isServerReachable && keycloak.authenticated && !isAuthorized)}>
<Typography variant='h1'>Waiting for verification...</Typography>
<CircularProgress />
</Backdrop>
</AuthContextProvider>
);
};
Expand Down

0 comments on commit 581ca68

Please sign in to comment.