diff --git a/src/auth/hooks/useAuthParameters.ts b/src/auth/hooks/useAuthParameters.ts new file mode 100644 index 000000000..c2a671799 --- /dev/null +++ b/src/auth/hooks/useAuthParameters.ts @@ -0,0 +1,20 @@ +import useLocalStorage from "@dashboard/hooks/useLocalStorage"; + +import { loginCallbackPath } from "../urls"; + +export const useAuthParameters = () => { + const [requestedExternalPluginId, setRequestedExternalPluginId] = + useLocalStorage("requestedExternalPluginId", null); + const [fallbackUri, setFallbackUri] = useLocalStorage( + "externalLoginFallbackUri", + null, + ); + + return { + requestedExternalPluginId, + fallbackUri: fallbackUri === "null" ? "/" : fallbackUri, + isCallbackPath: location.pathname.includes(loginCallbackPath), + setRequestedExternalPluginId, + setFallbackUri, + }; +}; diff --git a/src/auth/hooks/useAuthRedirection.ts b/src/auth/hooks/useAuthRedirection.ts new file mode 100644 index 000000000..03d6b98bb --- /dev/null +++ b/src/auth/hooks/useAuthRedirection.ts @@ -0,0 +1,60 @@ +import { getAppMountUri } from "@dashboard/config"; +import { getAppMountUriForRedirect } from "@dashboard/utils/urls"; +import { useEffect } from "react"; +import urlJoin from "url-join"; +import useRouter from "use-react-router"; + +import { useUser } from ".."; +import { loginCallbackPath } from "../urls"; +import { useAuthParameters } from "./useAuthParameters"; + +const PLUGIN_ID_PARAM = "saleorPluginId"; + +export const useAuthRedirection = () => { + const router = useRouter(); + const params = new URLSearchParams(router.location.search); + const shouldRedirect = params.has(PLUGIN_ID_PARAM); + const { authenticated, authenticating, requestLoginByExternalPlugin } = + useUser(); + const { setRequestedExternalPluginId } = useAuthParameters(); + const pluginId = params.get(PLUGIN_ID_PARAM); + + const handleAuthentication = async () => { + setRequestedExternalPluginId(pluginId); + + const redirectUri = urlJoin( + window.location.origin, + getAppMountUriForRedirect(), + loginCallbackPath, + ); + + const response = await requestLoginByExternalPlugin(pluginId, { + redirectUri, + }); + const data = JSON.parse(response?.authenticationData || ""); + + if (data && !response?.errors?.length) { + window.location.href = data.authorizationUrl; + } + }; + + useEffect(() => { + if (!shouldRedirect) { + return; + } + + if (authenticated || authenticating) { + window.location.href = getAppMountUri(); + return; + } + + if (!authenticated && !authenticating) { + handleAuthentication(); + } + }, [shouldRedirect, authenticated, authenticating]); + + return { + authenticated, + authenticating: authenticating || shouldRedirect, + }; +}; diff --git a/src/auth/views/Login.tsx b/src/auth/views/Login.tsx index 2a388854f..da9a22780 100644 --- a/src/auth/views/Login.tsx +++ b/src/auth/views/Login.tsx @@ -1,5 +1,4 @@ import { useAvailableExternalAuthenticationsQuery } from "@dashboard/graphql"; -import useLocalStorage from "@dashboard/hooks/useLocalStorage"; import useNavigator from "@dashboard/hooks/useNavigator"; import { getAppMountUriForRedirect } from "@dashboard/utils/urls"; import React, { useEffect } from "react"; @@ -9,6 +8,7 @@ import useRouter from "use-react-router"; import { useUser } from ".."; import LoginPage from "../components/LoginPage"; import { LoginFormData } from "../components/LoginPage/types"; +import { useAuthParameters } from "../hooks/useAuthParameters"; import { loginCallbackPath, LoginUrlQueryParams } from "../urls"; interface LoginViewProps { @@ -29,15 +29,14 @@ const LoginView: React.FC = ({ params }) => { data: externalAuthentications, loading: externalAuthenticationsLoading, } = useAvailableExternalAuthenticationsQuery(); - const [ - requestedExternalPluginId, - setRequestedExternalPluginId, - ] = useLocalStorage("requestedExternalPluginId", null); - const [fallbackUri, setFallbackUri] = useLocalStorage( - "externalLoginFallbackUri", - null, - ); + const { + fallbackUri, + requestedExternalPluginId, + isCallbackPath, + setFallbackUri, + setRequestedExternalPluginId, + } = useAuthParameters(); const handleSubmit = async (data: LoginFormData) => { const result = await login(data.email, data.password); @@ -70,15 +69,13 @@ const LoginView: React.FC = ({ params }) => { }); setRequestedExternalPluginId(null); if (result && !result?.errors?.length) { - navigate(fallbackUri ?? "/"); + navigate(fallbackUri); setFallbackUri(null); } }; useEffect(() => { const { code, state } = params; - const isCallbackPath = location.pathname.includes(loginCallbackPath); - const externalAuthParamsExist = code && state && isCallbackPath; const externalAuthNotPerformed = !authenticating && !errors.length; diff --git a/src/index.tsx b/src/index.tsx index 9f96f48a6..2e28e8dcc 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -20,10 +20,11 @@ import { ExternalAppProvider } from "./apps/components/ExternalAppContext"; import { AppSections } from "./apps/urls"; import AttributeSection from "./attributes"; import { attributeSection } from "./attributes/urls"; -import Auth, { useUser } from "./auth"; +import Auth from "./auth"; import AuthProvider from "./auth/AuthProvider"; import LoginLoading from "./auth/components/LoginLoading/LoginLoading"; import SectionRoute from "./auth/components/SectionRoute"; +import { useAuthRedirection } from "./auth/hooks/useAuthRedirection"; import CategorySection from "./categories"; import ChannelsSection from "./channels"; import { channelsSection } from "./channels/urls"; @@ -145,7 +146,7 @@ const App: React.FC = () => ( const Routes: React.FC = () => { const intl = useIntl(); const [, dispatchAppState] = useAppState(); - const { authenticated, authenticating } = useUser(); + const { authenticated, authenticating } = useAuthRedirection(); const { channel } = useAppChannel(false);