React Native: getCredentials returning undefined for Android, production app only

By necessity, this will be a long question due to the strange behaviour we are seeing, which needs fully explaining. Firstly I would like reference these 2 topics:

…and this Github issue linked from the first topic:

…as we are essentially experiencing the exact same issue, but I can add more detail about our scenario. We have been unable to resolve despite hours of tedious trial and error testing and countless app builds.

This issue is now the single blocker, preventing launch or our new Fintech React Native app

** App Setup**

  • We have a React Native app built using Expo framework and managed workflow, which targets iOS, Android and Web (web not too relevant here, see below)
  • We’re on Expo SDK 45
  • We’re using Auth0 provided react-native-auth0 library version 2.16.0
  • For web, this is switched out for @auth0/auth0-react where we have no current issues - not mentioned further here
  • We are using functional components and hooks, hence using the useAuth0 hook, and from this the authorize and getCredentials methods
  • We currently offer login/register via 3 methods (all via Auth0):
    • Google
    • Apple
    • Passwordless - this operates via backend and Auth0 management API and we have no issues here - not mentioned again

Environments

  • We have the following 3 application environments, and for each we build the iOS and Android apps:
    • Development - an Expo “custom dev client” build via EAS containing all the native libraries we need, including auth0
    • Staging - a “Full” normal app build via EAS - essentially an exact copy of Production, with slightly different configuration
    • Production - a “Full” normal app build via EAS
  • So, for clarity, we have a single Expo project from which we create 3x builds (for each OS) via EAS, one for each environment. From a Google and Apple store perspective, there are 2 apps each - a Staging and Production version which would be identical apart from the “baked” in config and bundle identifiers

Regarding Staging and Production:

  • All EAS settings (eas.json) are identical except a channel identifier
  • App config (app.config.js) is identical except where we swap out config items, including for example the auth0Domain value for the react-native-auth0 config plugin
  • An environment file is then loaded by the app based on the channel for all other config, again including auth0 variables such as domain, clientId, audience, scopes to be fed to the Auth0Provider

Each of our 3 environments has a separate Auth0 tenant, configured in the same way

  • Development → Development Tenant (free plan)
  • Staging → Staging Tenant (free plan)
  • Production → Production Tenant (paid plan - B2C Essentials)
    Configuration has been checked multiple times and all are in-line - the only difference with Production is that it has a custom domain configured

The Issue

Very specifically, the issue we are experiencing ONLY affects the Android build in the Production environment.

ALL OTHER builds and environments operate as expected. Indeed, through a series of app rebuilds (changing config and the domain value for react-native-auth0 config plugin), it has been proven that the following all work:

  • iOS - works in all cases
  • Development Build - works in all cases
  • Staging Build - works in all cases for all OS, including when it is re-configured to point at the Production Auth0 Tenant
  • Production Build - works for iOS only

Conversely:

  • Production Build NEVER works for Android - this includes when it is re-configured to point at the Staging Auth0 Tenant

By process of elimination, this suggests that:

  • There is no problem with the Auth0 tenant configuration
  • There is no problem with the Development/Staging builds
    …and therefore specifically pointing at the Production app build, however as mentioned above, this is build via EAS in an identical manner to Staging app.

As per the linked issues at the top, the specific problem is that getCredentials returns undefined following the call to authorize. This is despite the authorization working successfully, both in terms of redirecting back to the app, and indeed a successful login recorded by Auth0 in Monitoring->Logs. The code snipped below shows the simple call with comments on the issue:

try {
await authorize({
scope: auth0Scopes,
connection,
})
Logger.debug(Calling getCredentials...)
const token = await getCredentials(auth0Scopes)
//Here token is undefined in the case mentioned above for Android ONLY on our production build
if(token) {
//This method would proceed to setup our user in local state but is not called because token is undefined
await setUserWithToken(token, dispatch)
} else {
//So we hit this logging line for Android ONLY on our production build
Logger.error(Could not get authentication token)
}
} catch (e) {
Logger.error(Login failed: ${JSON.stringify(e)})
}

We are currently at a loss on how to resolve this issue as the fact that it works in all other builds, environments and iOS suggests there is no issue with our code.

Taking a look inside the react-native-auth0 package, I note that it IS seemingly possible for the getCredentials method to return undefined - looking at src\hooks\auth0-provider.js if the call to credentialsManager throws an exception:

const getCredentials = useCallback(
async (…options) => {
try {
return await client.credentialsManager.getCredentials(…options);
} catch (error) {
dispatch({type: ‘ERROR’, error});
return;
}
},
[client],
);

Would appreciate help with this issue - as mentioned above, it is now the single blocker preventing our launch - if we cannot resolve, we may have a very painful job of ripping out auth0 for another authentication solution.

1 Like