Describe the bug?
We use @okta/okta-react-native@2.17.0 in a production app and after upgrading to Expo SDK 56 (React Native 0.85, New Architecture enabled), email/password login via signIn() is completely broken due to two separate issues:
Issue 1: @okta/okta-auth-js — fetch fails in React Native 0.85 New Architecture
In fetchRequest.js, fetch is resolved as:
var fetch = window.fetch || crossFetch;
In React Native 0.85 with New Architecture (bridgeless mode), window.fetch is undefined and crossFetch does not function correctly in the RN environment. The POST request to /api/v1/authn receives no response.
Root cause: The New Architecture uses a JSI-based runtime where window globals behave differently. The existing fix from PR #360 (adding "react-native" field to package.json for correct ponyfill resolution) does not fully resolve this under the new bundler/runtime behavior.
Suggested fix: Use globalThis.fetch instead of window.fetch, or add RN environment detection that uses the global fetch directly. Alternatively, document the httpRequestClient option more prominently as the recommended approach for React Native.
Issue 2: Native iOS SDK — URLSession.shared is intercepted by Expo
The authenticate(withSessionToken:) method in the native OktaOidc iOS SDK uses URLSession.shared (via OKTURLSessionProvider.session() → RedirectBlockingURLSessionDelegate.shared). Expo SDK 56 registers a URLProtocol interceptor on the shared session for network debugging (ExpoRequestInterceptorProtocol in expo-dev-launcher).
When the /authorize endpoint responds with a 302 redirect to a custom URL scheme (e.g. com.example.myapp://callback?code=...), the interceptor attempts to follow the redirect but fails because it's not an HTTP scheme. The native SDK then receives nil as the response, resulting in:
Error: Sign in was not authorized
code: '-1000'
detail: Authorization Error: Authentication Error: No response
This is the same issue reported in #450 and confirmed in okta-oidc-ios PR #362.
Note: This affects both dev and production builds if any library registers a URLProtocol on URLSession.shared.
Suggested fixes:
- Use a dedicated
URLSession(configuration: .default) instead of .shared so that third-party URLProtocol registrations don't affect the SDK.
- Alternatively, use
ASWebAuthenticationSession for the authenticate(withSessionToken:) flow as well, since it natively handles custom-scheme redirects.
Our current workaround
We created a yarn patch that modifies the signIn function in @okta/okta-react-native/index.js so that after a successful signInWithCredentials, instead of calling authenticate({ sessionToken }), it calls signInWithBrowser({ sessionToken, noSSO: true }). This works but has the drawback of briefly showing a system browser sheet during login.
What is expected to happen?
signIn({ username, password }) should complete the full authentication flow (credentials → session token → token exchange) without errors on React Native 0.85+ with New Architecture enabled.
- The
fetch call to /api/v1/authn should succeed regardless of the JS runtime's window global state.
- The native iOS token exchange (
authenticate(withSessionToken:)) should successfully handle the 302 redirect to a custom URL scheme without being intercepted by third-party URLProtocol handlers registered on URLSession.shared.
- The SDK should be compatible with Expo SDK 56 and React Native's New Architecture without requiring patches.
What is the actual behavior?
Issue 1: fetch failure
Calling signIn({ username, password }) triggers a request to /api/v1/authn via okta-auth-js. The request silently fails — no response is returned, no network error is thrown. The Promise never resolves. In some configurations, fetch evaluates to false or undefined, causing a TypeError: fetch is not a function crash.
Issue 2: iOS token exchange failure
After signInWithCredentials succeeds and returns a valid sessionToken, the subsequent call to authenticate({ sessionToken }) fails on iOS with:
Error: Sign in was not authorized
code: '-1000'
detail: Authorization Error: Authentication Error: No response
The Okta server logs show a successful /authorize call with a 302 redirect to the custom scheme. The native SDK never receives the redirect response because Expo's URLProtocol interceptor consumes it. Android is not affected by Issue 2.
Reproduction Steps?
- Create a React Native app with Expo SDK 56 (React Native 0.85) and New Architecture enabled.
- Install
@okta/okta-react-native@2.17.0.
- Configure Okta with a custom redirect URI using a custom URL scheme (e.g.
com.example.myapp://callback).
- Call
createConfig(...) with valid Okta configuration.
- Call
signIn({ username: '...', password: '...' }) with valid credentials.
For Issue 1: The fetch call inside okta-auth-js to /api/v1/authn fails silently or throws TypeError: fetch is not a function.
For Issue 2 (iOS only): Even if Issue 1 is patched (e.g. by providing a custom httpRequestClient), the native authenticate({ sessionToken }) step fails with error code -1000 and message "No response". This is reproducible on both Simulator and physical device. Android completes the flow successfully with the same configuration.
Minimal reproduction path for Issue 2:
- The issue is triggered specifically when
expo-dev-launcher (or any library) registers a URLProtocol on URLSession.shared.
- Removing
expo-dev-launcher from the build resolves the iOS issue, but this is not a viable solution for development builds.
Additional Information?
No response
SDK Version
SDK Version
@okta/okta-react-native: 2.17.0
react-native: 0.85.x
expo: ~56.x
Build Information
Build Information
- iOS deployment target: 15.1
- New Architecture: enabled
- Bridgeless mode: enabled
- Hermes: enabled
Describe the bug?
We use
@okta/okta-react-native@2.17.0in a production app and after upgrading to Expo SDK 56 (React Native 0.85, New Architecture enabled), email/password login viasignIn()is completely broken due to two separate issues:Issue 1:
@okta/okta-auth-js— fetch fails in React Native 0.85 New ArchitectureIn
fetchRequest.js, fetch is resolved as:In React Native 0.85 with New Architecture (bridgeless mode),
window.fetchisundefinedandcrossFetchdoes not function correctly in the RN environment. The POST request to/api/v1/authnreceives no response.Root cause: The New Architecture uses a JSI-based runtime where
windowglobals behave differently. The existing fix from PR #360 (adding"react-native"field topackage.jsonfor correct ponyfill resolution) does not fully resolve this under the new bundler/runtime behavior.Suggested fix: Use
globalThis.fetchinstead ofwindow.fetch, or add RN environment detection that uses the global fetch directly. Alternatively, document thehttpRequestClientoption more prominently as the recommended approach for React Native.Issue 2: Native iOS SDK —
URLSession.sharedis intercepted by ExpoThe
authenticate(withSessionToken:)method in the nativeOktaOidciOS SDK usesURLSession.shared(viaOKTURLSessionProvider.session()→RedirectBlockingURLSessionDelegate.shared). Expo SDK 56 registers aURLProtocolinterceptor on the shared session for network debugging (ExpoRequestInterceptorProtocolinexpo-dev-launcher).When the
/authorizeendpoint responds with a 302 redirect to a custom URL scheme (e.g.com.example.myapp://callback?code=...), the interceptor attempts to follow the redirect but fails because it's not an HTTP scheme. The native SDK then receivesnilas the response, resulting in:This is the same issue reported in #450 and confirmed in okta-oidc-ios PR #362.
Note: This affects both dev and production builds if any library registers a URLProtocol on
URLSession.shared.Suggested fixes:
URLSession(configuration: .default)instead of.sharedso that third-partyURLProtocolregistrations don't affect the SDK.ASWebAuthenticationSessionfor theauthenticate(withSessionToken:)flow as well, since it natively handles custom-scheme redirects.Our current workaround
We created a yarn patch that modifies the
signInfunction in@okta/okta-react-native/index.jsso that after a successfulsignInWithCredentials, instead of callingauthenticate({ sessionToken }), it callssignInWithBrowser({ sessionToken, noSSO: true }). This works but has the drawback of briefly showing a system browser sheet during login.What is expected to happen?
signIn({ username, password })should complete the full authentication flow (credentials → session token → token exchange) without errors on React Native 0.85+ with New Architecture enabled.fetchcall to/api/v1/authnshould succeed regardless of the JS runtime'swindowglobal state.authenticate(withSessionToken:)) should successfully handle the 302 redirect to a custom URL scheme without being intercepted by third-partyURLProtocolhandlers registered onURLSession.shared.What is the actual behavior?
Issue 1: fetch failure
Calling
signIn({ username, password })triggers a request to/api/v1/authnviaokta-auth-js. The request silently fails — no response is returned, no network error is thrown. The Promise never resolves. In some configurations,fetchevaluates tofalseorundefined, causing aTypeError: fetch is not a functioncrash.Issue 2: iOS token exchange failure
After
signInWithCredentialssucceeds and returns a validsessionToken, the subsequent call toauthenticate({ sessionToken })fails on iOS with:The Okta server logs show a successful
/authorizecall with a 302 redirect to the custom scheme. The native SDK never receives the redirect response because Expo's URLProtocol interceptor consumes it. Android is not affected by Issue 2.Reproduction Steps?
@okta/okta-react-native@2.17.0.com.example.myapp://callback).createConfig(...)with valid Okta configuration.signIn({ username: '...', password: '...' })with valid credentials.For Issue 1: The
fetchcall insideokta-auth-jsto/api/v1/authnfails silently or throwsTypeError: fetch is not a function.For Issue 2 (iOS only): Even if Issue 1 is patched (e.g. by providing a custom
httpRequestClient), the nativeauthenticate({ sessionToken })step fails with error code-1000and message "No response". This is reproducible on both Simulator and physical device. Android completes the flow successfully with the same configuration.Minimal reproduction path for Issue 2:
expo-dev-launcher(or any library) registers aURLProtocolonURLSession.shared.expo-dev-launcherfrom the build resolves the iOS issue, but this is not a viable solution for development builds.Additional Information?
No response
SDK Version
SDK Version
Build Information
Build Information