Supporting multiple domains in the SDK
chrisbruford opened this issue · 11 comments
Checklist
- The issue can be reproduced in the react-native-auth0 sample app (or N/A).
- I have looked into the Readme, Examples, and FAQ and have not found a suitable solution or answer.
- I have looked into the API documentation and have not found a suitable solution or answer.
- I have searched the issues and have not found a suitable solution or answer.
- I have searched the Auth0 Community forums and have not found a suitable solution or answer.
- I agree to the terms within the Auth0 Code of Conduct.
Description
Create a new Auth0Provider
with a different domain
prop still results in directing users to the initial domain
when using the authorize method provided by useAuth0
hook.
Worked on 2.17.4
Reproduction
- Initialise the
Auth0Provider
with any validdomain
prop - Initialise a new
Auth0Provider
with a new validdomain
prop - Observe that the login function provided by
useAuth0
still directs the browser to the initial domain
Additional context
We use multiple Auth0 Tenants to isolate users from different customers and in our React Native app we allow the user to select which customer they are from and thus we dynamically change the domain
being sent to the Auth0 SDK.
This worked well up until we upgraded to v3 and now it fails to change the domain. I have traced it through the auth0 SDK and found the domain change is successfully being propogated all the way to the NativeModule import; but the SDK still directs the browser window to the previously set domain. Seems like the domain gets cached somewhere (perhaps the useAuth0 hook using the old object?)
I understand that Organisations is the recommended approach to this use case now; but the use of auth0 tenenants is still listed as a supported method - and thus I believe this change to be a bug.
Note: this has already been asked on the forums but no answer has been given for over a year
react-native-auth0 version
3.0.1
React Native version
0.72.5
Expo version
49.0.0
Platform
Android
Platform version(s)
13
@chrisbruford This can be achieved by using 2 instances of auth0 class instance rather than hooks which can be initialized like this
import Auth0 from 'react-native-auth0';
const auth0 = new Auth0({
domain: 'YOUR_AUTH0_DOMAIN',
clientId: 'YOUR_AUTH0_CLIENT_ID',
});
However using you have to be careful using the credentials manager as we can store only 1 access token and using both the instances alternatively will definitely result in an error.
So i'd suggest limiting this use case just for authentication purpose and not credentials management.
@poovamraj does the fact that this behaviour is not consistent across iOS and Android (as this only happens on Android) not constitute this being a bug? it seems odd to me that the "solution" is to not use the hooks functionality...that seems more like a workaround to achieve the same behaviour on Android as we already get for free on iOS...and as you pointed out, has undocumented pitfalls to doing so?
@poovamraj I tried your approach which ended up looking like this:
const auth0 = useMemo(() => {
if (!workspace) return;
return new Auth0({
domain: workspace?.variables.AUTH0_DOMAIN,
clientId: workspace?.variables.AUTH0_CLIENT_ID,
});
}, [workspace]);
I then tried to login like this:
console.log({ domain: auth0?.auth.domain });
auth0?.webAuth
.authorize({
audience: workspace?.variables.AUTH0_AUDIENCE || 'https://inbanx/api',
})
.then((credentials) => {
...
})
The console.log
shows me the domain has changed, but the call to authorize
still directs me to the domain for the first workspace, regardless.
As I mentioned in my earlier comment, this doesn't behave like this on iOS even when using hooks.
@chrisbruford You are right! As you mentioned we only have 1 instance of Auth0
object in the native module. We have a hasValidAuth0Instance
check that will avoid initializeAuth0
if there is already an existing instance.
I have to check why the iOS native module is not performing this check properly as it would mean creating a new instance of the SDK each time a web authentication or credentials management call is made.
The proper way to support this would be is to have a list of auth0 instances in the native module and use the right one depending on the client id making the request. Or we should provide a method to invalidate the existing instance of Auth0 client.
On a similar note it would be good if the hasValidAuth0Instance
was smart enough to realise that the domain/clientID has changed and allow the initializeAuth0
to be made. Our App only has a single Auth0Provider at a time but before logging in you can switch from a production environment to a dev environment. This used to work fine in older versions of react-native-auth0 but now we're having to restart the entire App when there's an environment change.
I am also encountering this issue after upgrading from 2.x to 3.x. I used to be able to switch domain/clientId without having to restart the app and now, with 3.x, the app fails to authorize the user because the wrong domain/clientId is being used after creating a new instance of the default exported class.
If it's of interest to others, we've been able to workaround this behavior by calling the underlying initializeAuth0
function when the clientID and/or domain changes...
useEffect(() => {
// There is a "feature" in the react-native-auth0 library where it will only initialize the native
// layer once with the first clientID and domain it is given. Any changes to these values will have
// no impact until the app is restarted.
// See https://github.com/auth0/react-native-auth0/issues/747#issuecomment-1791128894
//
// This code works around that by calling the initializeAuth0 native function ourselves when the
// clientID or domain changes
NativeModules.A0Auth0.initializeAuth0(clientID, domain);
}, [clientID, domain]);
thanks for sharing a workaround, @mrbrentkelly!
We are planning to address this issue along with other improvements in the next major release coming up this quarter. I'll share exact timelines by the mid of June.
Hi everyone,
We've fixed this issue as part of version 4.0.0-beta.0 and more details about it can be found here
Closing this issue for now, feel free to re-open it, if you run into any issues
Hi @desusai7 et al,
I have installed 4.0.0-beta.0
to test if the issue has been resolved, and whilst iOS is working perfectly, I am still facing some issues on Android.
As per the V4 documentation, here is the value of my android/app/build.gradle
:
android {
defaultConfig {
// Is this holding back multiple domain support on android? Can I add multiple here somehow?
manifestPlaceholders = [auth0Domain: "tenant1.auth0.com", auth0Scheme: "${applicationId}.auth0"]
}
}
Then, similar to @chrisbruford, in our JavaScript code we dynamically switch the Domain & Client ID based on a user's selection during the login process:
import Auth0 from 'react-native-auth0';
const doAuthorization = async (domain: string, clientId: string): Promise<void> => {
const auth0 = new Auth0({ domain, clientId });
await auth0.webAuth.authorize({});
};
Whenever we call doAuthorization
with "tenant1.auth0.com"
, we see that the login works. However, whenever it is called with any other valid domain (not present in android/app/build.gradle
), the CORRECT web URL opens in a browser, but upon authenticating successfully it just hangs in the in-app-browser and never redirects back into our app.
So it seems like we're getting closer now that that correct domain opens up for authentication, but on Android it still doesn't appear to allow you to sign in. Any ideas or suggestions @desusai7?
- React Native Version:
0.73.9
- Android:
14
Oh okay, I have found a solution to the above issue. It is documented in the pull request referenced above (#931).
In addition to implementing version 4.0.0-beta.0
of this library, I also had to modify my android/app/src/main/AndroidManifest.xml
file to add the following:
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools">
<application ...>
<activity
android:name=".MainActivity" ...>
...
</activity>
+ <activity
+ android:name="com.auth0.android.provider.RedirectActivity"
+ tools:node="replace"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ <data
+ android:host="tenant1.auth0.com"
+ android:pathPrefix="/android/${applicationId}/callback"
+ android:scheme="${applicationId}.auth0" />
+ <data
+ android:host="tenant2.auth0.com"
+ android:pathPrefix="/android/${applicationId}/callback"
+ android:scheme="${applicationId}.auth0" />
+ </intent-filter>
+ </activity>
</application>
</manifest>
I also removed the manifestPlaceholders
option from my android/app/build.gradle
file:
android {
defaultConfig {
- manifestPlaceholders = [auth0Domain: "tenant1.auth0.com", auth0Scheme: "${applicationId}.auth0"]
}
}
Following the above steps, I was able to get our dynamic login across multiple tenants working again.
May I suggest putting this inside the installation documentation for your stable V4 release @desusai7, as it was quite confusing to implement given the differences to the latest installation instructions for Android.