Skip to content

Commit 886615e

Browse files
committed
fix(expo): make expo-auth-session and expo-web-browser optional dependencies
Convert top-level imports to dynamic imports so users who don't use SSO/OAuth don't need these packages installed. Follows the same pattern as useSignInWithApple.ios.ts.
1 parent 5b09fbf commit 886615e

4 files changed

Lines changed: 41 additions & 8 deletions

File tree

packages/expo/package.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,9 @@
153153
"expo-apple-authentication": {
154154
"optional": true
155155
},
156+
"expo-auth-session": {
157+
"optional": true
158+
},
156159
"expo-constants": {
157160
"optional": true
158161
},
@@ -164,6 +167,9 @@
164167
},
165168
"expo-secure-store": {
166169
"optional": true
170+
},
171+
"expo-web-browser": {
172+
"optional": true
167173
}
168174
},
169175
"engines": {

packages/expo/src/hooks/useOAuth.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { useSignIn, useSignUp } from '@clerk/react/legacy';
22
import type { OAuthStrategy, SetActive, SignInResource, SignUpResource } from '@clerk/shared/types';
3-
import * as AuthSession from 'expo-auth-session';
4-
import * as WebBrowser from 'expo-web-browser';
3+
import type * as WebBrowser from 'expo-web-browser';
54

65
import { errorThrower } from '../utils/errors';
76

@@ -46,6 +45,18 @@ export function useOAuth(useOAuthParams: UseOAuthFlowParams) {
4645
};
4746
}
4847

48+
// Dynamically import expo-auth-session and expo-web-browser only when needed
49+
let AuthSession: typeof import('expo-auth-session');
50+
let WebBrowserModule: typeof import('expo-web-browser');
51+
try {
52+
[AuthSession, WebBrowserModule] = await Promise.all([import('expo-auth-session'), import('expo-web-browser')]);
53+
} catch {
54+
return errorThrower.throw(
55+
'expo-auth-session and expo-web-browser are required for OAuth. ' +
56+
'Install them: npx expo install expo-auth-session expo-web-browser',
57+
);
58+
}
59+
4960
// Create a redirect url for the current platform and environment.
5061
//
5162
// This redirect URL needs to be whitelisted for your Clerk production instance via
@@ -64,7 +75,7 @@ export function useOAuth(useOAuthParams: UseOAuthFlowParams) {
6475

6576
const { externalVerificationRedirectURL } = signIn.firstFactorVerification;
6677

67-
const authSessionResult = await WebBrowser.openAuthSessionAsync(
78+
const authSessionResult = await WebBrowserModule.openAuthSessionAsync(
6879
// @ts-ignore
6980
externalVerificationRedirectURL.toString(),
7081
oauthRedirectUrl,

packages/expo/src/hooks/useSSO.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@ import type {
66
SignInResource,
77
SignUpResource,
88
} from '@clerk/shared/types';
9-
import * as AuthSession from 'expo-auth-session';
10-
import * as WebBrowser from 'expo-web-browser';
9+
import type * as WebBrowser from 'expo-web-browser';
1110

1211
import { errorThrower } from '../utils/errors';
1312

@@ -48,6 +47,18 @@ export function useSSO() {
4847
};
4948
}
5049

50+
// Dynamically import expo-auth-session and expo-web-browser only when needed
51+
let AuthSession: typeof import('expo-auth-session');
52+
let WebBrowserModule: typeof import('expo-web-browser');
53+
try {
54+
[AuthSession, WebBrowserModule] = await Promise.all([import('expo-auth-session'), import('expo-web-browser')]);
55+
} catch {
56+
return errorThrower.throw(
57+
'expo-auth-session and expo-web-browser are required for SSO. ' +
58+
'Install them: npx expo install expo-auth-session expo-web-browser',
59+
);
60+
}
61+
5162
const { strategy, unsafeMetadata, authSessionOptions } = startSSOFlowParams ?? {};
5263

5364
/**
@@ -73,7 +84,7 @@ export function useSSO() {
7384
return errorThrower.throw('Missing external verification redirect URL for SSO flow');
7485
}
7586

76-
const authSessionResult = await WebBrowser.openAuthSessionAsync(
87+
const authSessionResult = await WebBrowserModule.openAuthSessionAsync(
7788
externalVerificationRedirectURL.toString(),
7889
redirectUrl,
7990
authSessionOptions,

packages/expo/src/provider/ClerkProvider.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import '../polyfills';
33
import type { ClerkProviderProps as ReactClerkProviderProps } from '@clerk/react';
44
import { InternalClerkProvider as ClerkReactProvider, type Ui } from '@clerk/react/internal';
55
import * as SecureStore from 'expo-secure-store';
6-
import * as WebBrowser from 'expo-web-browser';
76
import { useEffect, useRef } from 'react';
87
import { Platform } from 'react-native';
98

@@ -263,7 +262,13 @@ export function ClerkProvider<TUi extends Ui = Ui>(props: ClerkProviderProps<TUi
263262

264263
if (isWeb()) {
265264
// This is needed in order for useOAuth to work correctly on web.
266-
WebBrowser.maybeCompleteAuthSession();
265+
// Must stay synchronous during render to catch the redirect URL before children mount.
266+
try {
267+
const WebBrowser = require('expo-web-browser');
268+
WebBrowser.maybeCompleteAuthSession();
269+
} catch {
270+
// expo-web-browser not installed — SSO/OAuth on web won't work
271+
}
267272
}
268273

269274
return (

0 commit comments

Comments
 (0)