diff --git a/.changeset/fix-oauth-prefetch-race.md b/.changeset/fix-oauth-prefetch-race.md new file mode 100644 index 000000000..9cf755b02 --- /dev/null +++ b/.changeset/fix-oauth-prefetch-race.md @@ -0,0 +1,10 @@ +--- +"@crossmint/client-sdk-react-ui": patch +--- + +Fix OAuth URL prefetch race condition when auth dialog opens before initialization completes. + +- Gate prefetch on `jwt == null` instead of `getAuthStatus() === "logged-out"` so the prefetch still runs when the dialog is open during initialization. +- Skip prefetch when `crossmintAuth` is not yet available to avoid fetching with a null client. +- Initialize `isLoadingOauthUrlMap` to `false` so consumers are not stuck in a loading state when the prefetch has not started. +- Strengthen URL validation to reject empty strings in addition to null/undefined. diff --git a/packages/client/ui/react-ui/src/hooks/useOAuthWindowListener.ts b/packages/client/ui/react-ui/src/hooks/useOAuthWindowListener.ts index 0fc7a6891..a879ca0d9 100644 --- a/packages/client/ui/react-ui/src/hooks/useOAuthWindowListener.ts +++ b/packages/client/ui/react-ui/src/hooks/useOAuthWindowListener.ts @@ -48,7 +48,7 @@ export const useOAuthWindowListener = (oauthUrlMap: OAuthUrlMap, setError: (erro const prefetchedUrl = oauthUrlMap[provider]; const resolvedUrl = prefetchedUrl || (await crossmintAuth?.getOAuthUrl(provider)); - if (resolvedUrl == null) { + if (!resolvedUrl) { throw new Error("Failed to resolve OAuth URL"); } baseUrl = new URL(resolvedUrl); diff --git a/packages/client/ui/react-ui/src/providers/CrossmintAuthProvider.tsx b/packages/client/ui/react-ui/src/providers/CrossmintAuthProvider.tsx index 3a049c96e..62881b279 100644 --- a/packages/client/ui/react-ui/src/providers/CrossmintAuthProvider.tsx +++ b/packages/client/ui/react-ui/src/providers/CrossmintAuthProvider.tsx @@ -128,7 +128,7 @@ function CrossmintAuthProviderContent({ defaultEmail, }} > - + {children} diff --git a/packages/client/ui/react-ui/src/providers/auth/OAuthFlowProvider.tsx b/packages/client/ui/react-ui/src/providers/auth/OAuthFlowProvider.tsx index d13260ddf..ecc39e464 100644 --- a/packages/client/ui/react-ui/src/providers/auth/OAuthFlowProvider.tsx +++ b/packages/client/ui/react-ui/src/providers/auth/OAuthFlowProvider.tsx @@ -38,7 +38,7 @@ export function OAuthFlowProvider({ const { setError } = useAuthForm(); const [oauthUrlMap, setOauthUrlMap] = useState(initialOAuthUrlMap); - const [isLoadingOauthUrlMap, setIsLoadingOauthUrlMap] = useState(true); + const [isLoadingOauthUrlMap, setIsLoadingOauthUrlMap] = useState(false); const { createPopupAndSetupListeners, @@ -47,6 +47,9 @@ export function OAuthFlowProvider({ } = useOAuthWindowListener(oauthUrlMap, setError); const preFetchAndSetOauthUrl = useCallback(async () => { + if (crossmintAuth == null) { + return; + } setIsLoadingOauthUrlMap(true); try { const oauthProviders = (loginMethods || []).filter(