From 9dfbd23c01401e13183ce370060e62b50120a7a1 Mon Sep 17 00:00:00 2001 From: Laura Beatris <48022589+LauraBeatris@users.noreply.github.com> Date: Tue, 14 Jan 2025 15:04:39 -0300 Subject: [PATCH] Refactor implementation --- .changeset/selfish-worms-switch.md | 4 +- .../expo/src/hooks/{useSso.ts => useSSO.ts} | 73 ++++++++----------- 2 files changed, 34 insertions(+), 43 deletions(-) rename packages/expo/src/hooks/{useSso.ts => useSSO.ts} (59%) diff --git a/.changeset/selfish-worms-switch.md b/.changeset/selfish-worms-switch.md index 3c6c5ce55e..b4cf08be6f 100644 --- a/.changeset/selfish-worms-switch.md +++ b/.changeset/selfish-worms-switch.md @@ -2,7 +2,7 @@ '@clerk/clerk-expo': minor --- -Introduces support for SSO with SAML +Introduce support for SSO with SAML - Introduce `useSSO` hook to support a wider range of SSO flow types -- Deprecated `useOAuth` in favor of new `useSSO` hook +- Deprecate `useOAuth` in favor of new `useSSO` hook diff --git a/packages/expo/src/hooks/useSso.ts b/packages/expo/src/hooks/useSSO.ts similarity index 59% rename from packages/expo/src/hooks/useSso.ts rename to packages/expo/src/hooks/useSSO.ts index 2a1d2560e2..b175190363 100644 --- a/packages/expo/src/hooks/useSso.ts +++ b/packages/expo/src/hooks/useSSO.ts @@ -7,18 +7,22 @@ import { errorThrower } from '../utils/errors'; export type UseSSOParams = { strategy: OAuthStrategy | EnterpriseSSOStrategy; - redirectUrl?: string; unsafeMetadata?: SignUpUnsafeMetadata; + redirectUrl?: string; }; export type StartSSOParams = { - redirectUrl?: string; - unsafeMetadata?: SignUpUnsafeMetadata; identifier?: string; + unsafeMetadata?: SignUpUnsafeMetadata; + redirectUrl?: string; }; export type StartSSOFlowReturnType = { - createdSessionId: string; + /** + * Session ID created upon sign-in completion, or null if incomplete. + * If incomplete, use signIn or signUp for next steps like MFA. + */ + createdSessionId: string | null; setActive?: SetActive; signIn?: SignInResource; signUp?: SignUpResource; @@ -26,83 +30,70 @@ export type StartSSOFlowReturnType = { }; export function useSSO(useSSOParams: UseSSOParams) { - const { strategy } = useSSOParams || {}; - if (!strategy) { - return errorThrower.throw('Missing strategy'); - } - const { signIn, setActive, isLoaded: isSignInLoaded } = useSignIn(); const { signUp, isLoaded: isSignUpLoaded } = useSignUp(); async function startFlow(startSSOFlowParams?: StartSSOParams): Promise { if (!isSignInLoaded || !isSignUpLoaded) { return { - createdSessionId: '', + createdSessionId: null, signIn, signUp, setActive, }; } - // Create a redirect url for the current platform and environment. - // - // This redirect URL needs to be whitelisted for your Clerk production instance via - // https://clerk.com/docs/reference/backend-api/tag/Redirect-URLs#operation/CreateRedirectURL - // - // For more information go to: - // https://docs.expo.dev/versions/latest/sdk/auth-session/#authsessionmakeredirecturi - const oauthRedirectUrl = + let createdSessionId = signIn.createdSessionId; + + const redirectUrl = startSSOFlowParams?.redirectUrl || useSSOParams.redirectUrl || AuthSession.makeRedirectUri({ path: 'sso-native-callback', }); - await signIn.create({ strategy, redirectUrl: oauthRedirectUrl, identifier: startSSOFlowParams?.identifier }); + await signIn.create({ + strategy: useSSOParams.strategy, + redirectUrl, + identifier: startSSOFlowParams?.identifier, + }); const { externalVerificationRedirectURL } = signIn.firstFactorVerification; - if (!externalVerificationRedirectURL) { - return errorThrower.throw('Missing external verification redirect URL for SSO flow'); + return errorThrower.throw( + 'Missing external verification redirect URL for SSO flow. This indicates an API issue - please contact support for assistance.', + ); } const authSessionResult = await WebBrowser.openAuthSessionAsync( externalVerificationRedirectURL.toString(), - oauthRedirectUrl, + redirectUrl, ); - - // @ts-expect-error - const { type, url } = authSessionResult || {}; - - // TODO: Check all the possible AuthSession results - // https://docs.expo.dev/versions/latest/sdk/auth-session/#returns-7 - if (type !== 'success') { + if (authSessionResult.type !== 'success' || !authSessionResult.url) { return { authSessionResult, - createdSessionId: '', + createdSessionId, setActive, signIn, signUp, }; } - const params = new URL(url).searchParams; + const params = new URL(authSessionResult.url).searchParams; + const rotatingTokenNonce = params.get('rotating_token_nonce'); + if (!rotatingTokenNonce) { + return errorThrower.throw( + 'Missing rotating_token_nonce in SSO callback. This indicates an API issue - please contact support for assistance.', + ); + } - const rotatingTokenNonce = params.get('rotating_token_nonce') || ''; await signIn.reload({ rotatingTokenNonce }); - - const { status, firstFactorVerification } = signIn; - - let createdSessionId = ''; - - if (status === 'complete') { - createdSessionId = signIn.createdSessionId!; - } else if (firstFactorVerification.status === 'transferable') { + if (signIn.firstFactorVerification.status === 'transferable') { await signUp.create({ transfer: true, unsafeMetadata: startSSOFlowParams?.unsafeMetadata || useSSOParams.unsafeMetadata, }); - createdSessionId = signUp.createdSessionId || ''; + createdSessionId = signUp.createdSessionId; } return {