ToolJet/frontend/src/Oauth/Authorize.jsx

187 lines
7.1 KiB
JavaScript

import React, { useEffect, useState } from 'react';
import useRouter from '@/_hooks/use-router';
import { aiOnboardingService, appService, authenticationService } from '@/_services';
import { Navigate } from 'react-router-dom';
import Configs from './Configs/Config.json';
import { getCookie } from '@/_helpers';
import { TJLoader } from '@/_ui/TJLoader/TJLoader';
import { onInvitedUserSignUpSuccess, onLoginSuccess } from '@/_helpers/platform/utils/auth.utils';
import { updateCurrentSession } from '@/_helpers/authorizeWorkspace';
import posthogHelper from '@/modules/common/helpers/posthogHelper';
import { fetchEdition } from '@/modules/common/helpers/utils';
export function Authorize({ navigate }) {
const [error, setError] = useState('');
const [inviteeEmail, setInviteeEmail] = useState();
const router = useRouter();
const organizationId = authenticationService.getLoginOrganizationId();
const organizationSlug = authenticationService.getLoginOrganizationSlug();
const redirectUrl = getCookie('redirectPath');
const signupOrganizationSlug = authenticationService.getSignupOrganizationSlug();
const inviteFlowIdentifier = authenticationService.getInviteFlowIndetifier();
useEffect(() => {
const errorMessage = router.query.error_description || router.query.error;
if (errorMessage) {
return setError(errorMessage);
}
if (!(router.query.origin && Configs[router.query.origin])) {
return setError('Login failed');
}
const configs = Configs[router.query.origin];
const authParams = {};
if (configs.responseType === 'hash') {
if (!window.location.hash) {
return setError('Login failed');
}
const params = new Proxy(new URLSearchParams(window.location.hash.substr(1)), {
get: (searchParams, prop) => searchParams.get(prop),
});
authParams.token = params[configs.params.token];
authParams.state = params[configs.params.state];
} else {
authParams.token = router.query[configs.params.token];
authParams.state = router.query[configs.params.state];
authParams.iss = router.query[configs.params.iss];
}
/* If the params has SAMLResponse the SAML auth is success */
if (router.query.saml_response_id) {
authParams.samlResponseId = router.query.saml_response_id;
}
let subsciption;
if (organizationId) {
subsciption = authenticationService.currentSession.subscribe((session) => {
//logged users should send tj-workspace-id when login to unauthorized workspace
if (session.authentication_status === false || session.current_organization_id) {
signIn(authParams, configs);
subsciption.unsubscribe();
}
});
} else {
signIn(authParams, configs);
}
// Disabled for useEffect not being called for updation
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const signIn = (authParams, configs) => {
const handleAuthResponse = ({ redirect_url, ...restResponse }) => {
const { organization_id, current_organization_id, email } = restResponse;
const event = `${redirect_url ? 'signup' : 'signin'}_${
router.query.origin === 'google' ? 'google' : router.query.origin === 'openid' ? 'openid' : 'github'
}`;
posthogHelper.initPosthog(restResponse);
posthogHelper.captureEvent(event, {
email,
workspace_id: organization_id || current_organization_id,
});
/* Precaution code to not take any previous values since there are two entry point to the app now (site and tooljet-app) */
authenticationService.deleteAllSSOCookies();
if (redirect_url) {
localStorage.setItem('ph-sso-type', router.query.origin); //for posthog event
window.location.href = redirect_url;
return;
}
if (restResponse?.organizationInviteUrl) onInvitedUserSignUpSuccess(restResponse, navigate);
else {
updateCurrentSession({
isUserLoggingIn: true,
});
onLoginSuccess(restResponse, navigate);
}
posthogHelper.initPosthog({ redirect_url, ...restResponse });
posthogHelper.captureEvent(event, {
email,
workspace_id: organization_id || current_organization_id,
});
};
const handleAuthError = (err) => {
console.log('SSO login error', err);
const details = err?.data?.message;
const inviteeEmail = details?.inviteeEmail;
if (inviteeEmail) setInviteeEmail(inviteeEmail);
let errorMessage = '';
if (details?.error && details?.data) {
errorMessage = `${details.error} ${details.data.join(', ')}`;
}
const errMessage = errorMessage || details?.error || details?.message || err?.error || 'something went wrong';
if (!inviteeEmail && inviteFlowIdentifier) {
/* Some unexpected error happened from the provider side. Need to retreive email to continue */
appService
.getInviteeDetails(inviteFlowIdentifier)
.then((response) => {
setInviteeEmail(response.email);
})
.catch(() => {
console.error('Error while fetching invitee details');
})
.finally(() => {
setError(`${configs.name} login failed - ${errMessage}`);
});
} else {
setError(`${configs.name} login failed - ${errMessage}`);
}
};
const hashParams = new URLSearchParams(window.location.hash.substring(1));
// FIXME: later create different component/login for cloud and ce/ee
const edition = fetchEdition();
if (edition === 'cloud') {
const isAiOnboarding =
hashParams.get('state')?.includes('tj_api_source=ai_onboarding') ||
router.query.state?.includes('tj_api_source=ai_onboarding');
const isNormalFlow = (organizationId || signupOrganizationSlug || inviteFlowIdentifier) && !isAiOnboarding;
if (isNormalFlow) {
/* For workspace signup and signin */
authenticationService
.signInViaOAuth(router.query.configId, router.query.origin, authParams)
.then(handleAuthResponse)
.catch(handleAuthError);
} else {
/* For ai onboarding */
aiOnboardingService
.signInViaOAuth(router.query.origin, authParams)
.then(handleAuthResponse)
.catch(handleAuthError);
}
return;
} else {
authenticationService
.signInViaOAuth(router.query.configId, router.query.origin, authParams)
.then(handleAuthResponse)
.catch(handleAuthError);
}
};
const baseRoute = signupOrganizationSlug ? '/signup' : '/login';
const slug = signupOrganizationSlug ? signupOrganizationSlug : organizationSlug;
const errorURL = `${baseRoute}${error && slug ? `/${slug}` : '/'}${
!signupOrganizationSlug && redirectUrl ? `?redirectTo=${redirectUrl}` : ''
}`;
return (
<div>
<TJLoader />
{error && (
<Navigate
replace
to={errorURL}
state={{
errorMessage: error && error,
...(inviteFlowIdentifier ? { organizationToken: inviteFlowIdentifier, inviteeEmail } : {}),
}}
/>
)}
</div>
);
}