mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-09-01 13:13:10 +00:00
fix: google refresh token silent callback (#10010)
* fix: google refresh token silent callback * refactor: update axios interceptor reference in context * refactor: address review comments
This commit is contained in:
parent
c81446e2be
commit
97ea3608bd
@ -18,7 +18,7 @@ import { MsalProvider } from '@azure/msal-react';
|
|||||||
import { LoginCallback } from '@okta/okta-react';
|
import { LoginCallback } from '@okta/okta-react';
|
||||||
import { AxiosError } from 'axios';
|
import { AxiosError } from 'axios';
|
||||||
import { CookieStorage } from 'cookie-storage';
|
import { CookieStorage } from 'cookie-storage';
|
||||||
import { isEmpty, isNil } from 'lodash';
|
import { isEmpty, isNil, isNumber } from 'lodash';
|
||||||
import { observer } from 'mobx-react';
|
import { observer } from 'mobx-react';
|
||||||
import React, {
|
import React, {
|
||||||
ComponentType,
|
ComponentType,
|
||||||
@ -43,7 +43,6 @@ import { AuthenticationConfiguration } from '../../../generated/configuration/au
|
|||||||
import { AuthType, User } from '../../../generated/entity/teams/user';
|
import { AuthType, User } from '../../../generated/entity/teams/user';
|
||||||
import jsonData from '../../../jsons/en';
|
import jsonData from '../../../jsons/en';
|
||||||
import {
|
import {
|
||||||
EXPIRY_THRESHOLD_MILLES,
|
|
||||||
extractDetailsFromToken,
|
extractDetailsFromToken,
|
||||||
getAuthConfig,
|
getAuthConfig,
|
||||||
getNameFromEmail,
|
getNameFromEmail,
|
||||||
@ -87,6 +86,9 @@ const userAPIQueryFields = 'profile,teams,roles';
|
|||||||
|
|
||||||
const isEmailVerifyField = 'isEmailVerified';
|
const isEmailVerifyField = 'isEmailVerified';
|
||||||
|
|
||||||
|
let requestInterceptor: number | null = null;
|
||||||
|
let responseInterceptor: number | null = null;
|
||||||
|
|
||||||
export const AuthProvider = ({
|
export const AuthProvider = ({
|
||||||
childComponentType,
|
childComponentType,
|
||||||
children,
|
children,
|
||||||
@ -242,26 +244,15 @@ export const AuthProvider = ({
|
|||||||
* Renew Id Token handler for all the SSOs.
|
* Renew Id Token handler for all the SSOs.
|
||||||
* This method will be called when the id token is about to expire.
|
* This method will be called when the id token is about to expire.
|
||||||
*/
|
*/
|
||||||
const renewIdToken = (): Promise<string> => {
|
const renewIdToken = async () => {
|
||||||
const onRenewIdTokenHandlerPromise = onRenewIdTokenHandler();
|
try {
|
||||||
|
const onRenewIdTokenHandlerPromise = onRenewIdTokenHandler();
|
||||||
|
onRenewIdTokenHandlerPromise && (await onRenewIdTokenHandlerPromise);
|
||||||
|
} catch (error) {
|
||||||
|
console.error((error as AxiosError).message);
|
||||||
|
}
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return localState.getOidcToken();
|
||||||
if (onRenewIdTokenHandlerPromise) {
|
|
||||||
onRenewIdTokenHandlerPromise
|
|
||||||
.then(() => {
|
|
||||||
resolve(localState.getOidcToken() || '');
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
if (error.message !== 'Frame window timed out') {
|
|
||||||
reject(error);
|
|
||||||
} else {
|
|
||||||
resolve(localState.getOidcToken() || '');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
reject('RenewIdTokenHandler is undefined');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -291,28 +282,24 @@ export const AuthProvider = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* It will set an timer for 50 secs before Token will expire
|
* It will set an timer for 5 mins before Token will expire
|
||||||
* If time if less then 50 secs then it will try to SilentSignIn
|
* If time if less then 5 mins then it will try to SilentSignIn
|
||||||
* It will also ensure that we have time left for token expiry
|
* It will also ensure that we have time left for token expiry
|
||||||
* This method will be call upon successful signIn
|
* This method will be call upon successful signIn
|
||||||
*/
|
*/
|
||||||
const startTokenExpiryTimer = () => {
|
const startTokenExpiryTimer = () => {
|
||||||
// Extract expiry
|
// Extract expiry
|
||||||
const { exp, isExpired, diff, timeoutExpiry } = extractDetailsFromToken();
|
const { isExpired, timeoutExpiry } = extractDetailsFromToken();
|
||||||
|
|
||||||
if (!isExpired && exp && diff && timeoutExpiry) {
|
if (!isExpired && isNumber(timeoutExpiry)) {
|
||||||
// Have 2m buffer before start trying for silent signIn
|
// Have 5m buffer before start trying for silent signIn
|
||||||
// If token is about to expire then start silentSignIn
|
// If token is about to expire then start silentSignIn
|
||||||
// else just set timer to try for silentSignIn before token expires
|
// else just set timer to try for silentSignIn before token expires
|
||||||
if (diff > EXPIRY_THRESHOLD_MILLES) {
|
clearTimeout(timeoutId);
|
||||||
clearTimeout(timeoutId);
|
const timerId = setTimeout(() => {
|
||||||
const timerId = setTimeout(() => {
|
|
||||||
trySilentSignIn();
|
|
||||||
}, timeoutExpiry);
|
|
||||||
setTimeoutId(Number(timerId));
|
|
||||||
} else {
|
|
||||||
trySilentSignIn();
|
trySilentSignIn();
|
||||||
}
|
}, timeoutExpiry);
|
||||||
|
setTimeoutId(Number(timerId));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -324,12 +311,6 @@ export const AuthProvider = ({
|
|||||||
clearTimeout(timeoutId);
|
clearTimeout(timeoutId);
|
||||||
}, [timeoutId]);
|
}, [timeoutId]);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
startTokenExpiryTimer();
|
|
||||||
|
|
||||||
return cleanup;
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const handleFailedLogin = () => {
|
const handleFailedLogin = () => {
|
||||||
setIsSigningIn(false);
|
setIsSigningIn(false);
|
||||||
setIsUserAuthenticated(false);
|
setIsUserAuthenticated(false);
|
||||||
@ -398,7 +379,17 @@ export const AuthProvider = ({
|
|||||||
*/
|
*/
|
||||||
const initializeAxiosInterceptors = () => {
|
const initializeAxiosInterceptors = () => {
|
||||||
// Axios Request interceptor to add Bearer tokens in Header
|
// Axios Request interceptor to add Bearer tokens in Header
|
||||||
axiosClient.interceptors.request.use(async function (config) {
|
if (requestInterceptor != null) {
|
||||||
|
axiosClient.interceptors.request.eject(requestInterceptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (responseInterceptor != null) {
|
||||||
|
axiosClient.interceptors.response.eject(responseInterceptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
requestInterceptor = axiosClient.interceptors.request.use(async function (
|
||||||
|
config
|
||||||
|
) {
|
||||||
const token: string = localState.getOidcToken() || '';
|
const token: string = localState.getOidcToken() || '';
|
||||||
if (token) {
|
if (token) {
|
||||||
if (config.headers) {
|
if (config.headers) {
|
||||||
@ -414,7 +405,7 @@ export const AuthProvider = ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Axios response interceptor for statusCode 401,403
|
// Axios response interceptor for statusCode 401,403
|
||||||
axiosClient.interceptors.response.use(
|
responseInterceptor = axiosClient.interceptors.response.use(
|
||||||
(response) => response,
|
(response) => response,
|
||||||
(error) => {
|
(error) => {
|
||||||
if (error.response) {
|
if (error.response) {
|
||||||
@ -573,6 +564,9 @@ export const AuthProvider = ({
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchAuthConfig();
|
fetchAuthConfig();
|
||||||
|
startTokenExpiryTimer();
|
||||||
|
|
||||||
|
return cleanup;
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -625,6 +619,7 @@ export const AuthProvider = ({
|
|||||||
setLoadingIndicator,
|
setLoadingIndicator,
|
||||||
handleSuccessfulLogin,
|
handleSuccessfulLogin,
|
||||||
handleUserCreated,
|
handleUserCreated,
|
||||||
|
updateAxiosInterceptors: initializeAxiosInterceptors,
|
||||||
jwtPrincipalClaims,
|
jwtPrincipalClaims,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -74,6 +74,7 @@ const OidcAuthenticator = forwardRef<AuthenticatorRef, Props>(
|
|||||||
isSigningIn,
|
isSigningIn,
|
||||||
setIsSigningIn,
|
setIsSigningIn,
|
||||||
setLoadingIndicator,
|
setLoadingIndicator,
|
||||||
|
updateAxiosInterceptors,
|
||||||
} = useAuthContext();
|
} = useAuthContext();
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
const { userDetails, newUser } = AppState;
|
const { userDetails, newUser } = AppState;
|
||||||
@ -94,7 +95,10 @@ const OidcAuthenticator = forwardRef<AuthenticatorRef, Props>(
|
|||||||
|
|
||||||
// Performs silent signIn and returns with IDToken
|
// Performs silent signIn and returns with IDToken
|
||||||
const signInSilently = async () => {
|
const signInSilently = async () => {
|
||||||
return userManager.signinSilent().then((user) => user.id_token);
|
const user = await userManager.signinSilent();
|
||||||
|
localState.setOidcToken(user.id_token);
|
||||||
|
|
||||||
|
return user.id_token;
|
||||||
};
|
};
|
||||||
|
|
||||||
useImperativeHandle(ref, () => ({
|
useImperativeHandle(ref, () => ({
|
||||||
@ -158,6 +162,7 @@ const OidcAuthenticator = forwardRef<AuthenticatorRef, Props>(
|
|||||||
}}
|
}}
|
||||||
onSuccess={(user) => {
|
onSuccess={(user) => {
|
||||||
localState.setOidcToken(user.id_token);
|
localState.setOidcToken(user.id_token);
|
||||||
|
updateAxiosInterceptors();
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
|
@ -30,11 +30,7 @@ import { isDev } from './EnvironmentUtils';
|
|||||||
|
|
||||||
export let msalInstance: IPublicClientApplication;
|
export let msalInstance: IPublicClientApplication;
|
||||||
|
|
||||||
export const EXPIRY_THRESHOLD_MILLES = 2 * 60 * 1000;
|
export const EXPIRY_THRESHOLD_MILLES = 5 * 60 * 1000;
|
||||||
|
|
||||||
export const getOidcExpiry = () => {
|
|
||||||
return new Date(Date.now() + 60 * 60 * 24 * 1000);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getRedirectUri = (callbackUrl: string) => {
|
export const getRedirectUri = (callbackUrl: string) => {
|
||||||
return isDev()
|
return isDev()
|
||||||
@ -279,7 +275,10 @@ export const extractDetailsFromToken = () => {
|
|||||||
const dateNow = Date.now();
|
const dateNow = Date.now();
|
||||||
|
|
||||||
const diff = exp && exp * 1000 - dateNow;
|
const diff = exp && exp * 1000 - dateNow;
|
||||||
const timeoutExpiry = diff && diff - EXPIRY_THRESHOLD_MILLES;
|
const timeoutExpiry =
|
||||||
|
diff && diff > EXPIRY_THRESHOLD_MILLES
|
||||||
|
? diff - EXPIRY_THRESHOLD_MILLES
|
||||||
|
: 0;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
exp,
|
exp,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user