# Frequently Asked Questions 1. [How can I have separate Auth0 domains for each environment on Android?](#1-how-can-i-have-separate-auth0-domains-for-each-environment-on-android) 2. [How can I disable the iOS _login_ alert box?](#2-how-can-i-disable-the-ios-login-alert-box) 3. [How can I disable the iOS _logout_ alert box?](#3-how-can-i-disable-the-ios-logout-alert-box) 4. [Is there a way to disable the iOS _login_ alert box without `ephemeralSession`?](#4-is-there-a-way-to-disable-the-ios-login-alert-box-without-ephemeralsession) 5. [How can I change the message in the iOS alert box?](#5-how-can-i-change-the-message-in-the-ios-alert-box) 6. [How can I programmatically close the iOS alert box?](#6-how-can-i-programmatically-close-the-ios-alert-box) 7. [Auth0 web browser gets killed when going to the background on Android](#7-auth0-web-browser-gets-killed-when-going-to-the-background-on-android) 8. [How to resolve the _Failed to start this transaction, as there is an active transaction at the moment_ error?](#8-how-to-resolve-the-failed-to-start-this-transaction-as-there-is-an-active-transaction-at-the-moment-error) 9. [Why doesn't `await authorize()` work on the web? How do I handle login?](#9-why-doesnt-await-authorize-work-on-the-web-how-do-i-handle-login) 10. [Why do my users get logged out frequently? How do I keep them logged in?](#10-why-do-my-users-get-logged-out-frequently-how-do-i-keep-them-logged-in) 11. [How can I prompt users to the login page versus signup page?](#11-how-can-i-prompt-users-to-the-login-page-versus-signup-page) 12. [Why does `getCredentials()` return an opaque access token on web instead of a JWT?](#12-why-does-getcredentials-return-an-opaque-access-token-on-web-instead-of-a-jwt) 13. [What is DPoP and should I enable it?](#13-what-is-dpop-and-should-i-enable-it) 14. [How do I migrate existing users to DPoP?](#14-how-do-i-migrate-existing-users-to-dpop) 15. [How do I know if my tokens are using DPoP?](#15-how-do-i-know-if-my-tokens-are-using-dpop) 16. [What happens if I disable DPoP after enabling it?](#16-what-happens-if-i-disable-dpop-after-enabling-it) 17. [Why does the app hang or freeze during Social Login (Google, Facebook, etc.)?](#17-why-does-the-app-hang-or-freeze-during-social-login-google-facebook-etc) 18. [How do I refresh the user profile (e.g. `emailVerified`) after it changes on the server?](#18-how-do-i-refresh-the-user-profile-eg-emailverified-after-it-changes-on-the-server) ## 1. How can I have separate Auth0 domains for each environment on Android? This library internally declares a `RedirectActivity` along with an **intent-filter** in its Android Manifest file to handle the Web Auth callback and logout URLs. While this approach prevents the developer from adding an activity declaration to their apps's Android Manifest file, it requires the use of [Manifest Placeholders](https://developer.android.com/studio/build/manage-manifests#inject_build_variables_into_the_manifest). Alternatively, you can re-declare the `RedirectActivity` in the `AndroidManifest.xml` file with your own **intent-filter** so it overrides the library's default one. If you do this then the `manifestPlaceholders` don't need to be set as long as the activity contains `tools:node="replace"` like in the snippet below. ```xml ``` ## 2. How can I disable the iOS _login_ alert box? ![ios-sso-alert](assets/ios-sso-alert.png) Under the hood, react-native-auth0 uses `ASWebAuthenticationSession` by default to perform web-based authentication, which is the [API provided by Apple](https://developer.apple.com/documentation/authenticationservices/aswebauthenticationsession) for such purpose. That alert box is displayed and managed by `ASWebAuthenticationSession`, not by react-native-auth0, because by default this API will store the session cookie in the shared Safari cookie jar. This makes single sign-on (SSO) possible. According to Apple, that requires user consent. > **Note** > See [this blog post](https://developer.okta.com/blog/2022/01/13/mobile-sso) for a detailed overview of SSO on iOS. ### Use ephemeral sessions If you don't need SSO, you can disable this behavior by adding `ephemeralSession: true` to the login call. This will configure `ASWebAuthenticationSession` to not store the session cookie in the shared cookie jar, as if using an incognito browser window. With no shared cookie, `ASWebAuthenticationSession` will not prompt the user for consent. ```js auth0.webAuth .authorize( { scope: 'openid profile email' }, { ephemeralSession: true } // No SSO, therefore no alert box ) .then((credentials) => console.log(credentials)) .catch((error) => console.log(error)); ``` Note that with `ephemeralSession: true` you don't need to call `clearSession` at all. Just clearing the credentials from the app will suffice. What `clearSession` does is clear the shared session cookie, so that in the next login call the user gets asked to log in again. But with `ephemeralSession: true` there will be no shared cookie to remove. You still need to call `clearSession` on Android, though, as `ephemeralSession` is iOS-only. ### Use `SFSafariViewController` An alternative is to use `SFSafariViewController` instead of `ASWebAuthenticationSession`. You can do so with the built-in `SFSafariViewController` Web Auth provider: ```js auth0.webAuth .authorize( { scope: 'openid profile email' }, { useSFSafariViewController: true } // Use SFSafariViewController ) .then((credentials) => console.log(credentials)) .catch((error) => console.log(error)); ``` > **Note** > Since `SFSafariViewController` does not share cookies with the Safari app, SSO will not work either. But it will keep its own cookies, so you can use it to perform SSO between your app and your website as long as you open it inside your app using `SFSafariViewController`. This also means that any feature that relies on the persistence of cookies will work as expected. ## 3. How can I disable the iOS _logout_ alert box? ![ios-sso-alert](assets/ios-sso-alert.png) Since `clearSession` needs to use `ASWebAuthenticationSession` as well to clear the shared session cookie, the same alert box will be displayed. If you need SSO and/or are willing to tolerate the alert box on the login call, but would prefer to get rid of it when calling `clearSession`, you can simply not call `clearSession` and just clear the credentials from the app. This means that the shared session cookie will not be removed, so to get the user to log in again you need to add the `prompt: 'login'` parameter to the _login_ call. ```js auth0.webAuth .authorize( { additionalParameters: { prompt: 'login' } }, // Ignore the cookie (if present) and show the login page { ephemeralSession: true } ) .then((credentials) => console.log(credentials)) .catch((error) => console.log(error)); ``` Otherwise, the browser modal will close right away and the user will be automatically logged in again, as the cookie will still be there. > **Warning** > Keeping the shared session cookie may not be an option if you have strong privacy and/or security requirements, for example in the case of a banking app. ## 4. Is there a way to disable the iOS _login_ alert box without `ephemeralSession`? No. According to Apple, storing the session cookie in the shared Safari cookie jar requires user consent. The only way to not have a shared cookie is to configure `ASWebAuthenticationSession` with `prefersEphemeralWebBrowserSession` set to `true`, which is what `ephemeralSession: true` does. ## 5. How can I change the message in the iOS alert box? This library has no control whatsoever over the alert box. Its contents cannot be changed. Unfortunately, that's a limitation of `ASWebAuthenticationSession`. ## 6. How can I programmatically close the iOS alert box? This library has no control whatsoever over the alert box. It cannot be closed programmatically. Unfortunately, that's a limitation of `ASWebAuthenticationSession`. ## 7. Auth0 web browser gets killed when going to the background on Android ### The problem When opening the Auth0 web browser to perform authentication, the Android system may kill the browser when the app goes to the background and you re-launch the app by pressing the app icon. This is a common behaviour if a user has MFA enabled for example and the user switches to another app to get the MFA code. You may have seen other issues where the usage of `singleTop` fixes this issue. However, other different libraries may be using `singleTask` and this can cause other issues if you change it. See these issues for more information: - [Android: OTP auth browser closes when minimising app](https://github.com/auth0/react-native-auth0/issues/921) - [Fixed authentication restart when the app is minimized ](https://github.com/auth0/react-native-auth0/pull/350) - [possibility to run with launchMode:singleTop?](https://github.com/auth0/react-native-auth0/issues/170) - [Android singleTask launch mode is required for react-native deep links](https://github.com/auth0/react-native-auth0/issues/556) ### Recovering the login (recommended) If the OS kills your app's process entirely while the browser is open (rather than just pausing the activity), the SDK can still complete the login on restart. Call `resumeSession()` once on cold start to recover it: ```js // With the Auth0 class const credentials = await auth0.webAuth.resumeSession(); // Or with hooks const { resumeSession } = useAuth0(); useEffect(() => { resumeSession(); }, [resumeSession]); ``` If a login was interrupted by process death, `resumeSession()` returns the recovered `Credentials`; otherwise it returns `null`. It is Android-only (a no-op resolving `null` on iOS/web) and requires no `MainActivity` changes, so it works in both bare React Native and Expo. See [Recovering Login After Process Death (Android)](EXAMPLES.md#recovering-login-after-process-death-android) for full examples. ### The solution (for `singleTask` launch mode) If your Android `launchMode` is set to `singleTask` (check your `AndroidManifest.xml`), that's why this is occurring. Unfortunately, this is not addressable by the react-native-auth0 library. This is [the same solution for the stripe-react-native library](https://github.com/stripe/stripe-react-native/issues/355#issuecomment-1701323254), but it also help other libraries that have the same issue. 1. Modify your `MainApplication`: ```diff public class MainApplication extends Application { + private ArrayList runningActivities = new ArrayList<>(); + public void addActivityToStack (Class cls) { + if (!runningActivities.contains(cls)) runningActivities.add(cls); + } + public void removeActivityFromStack (Class cls) { + if (runningActivities.contains(cls)) runningActivities.remove(cls); + } + public boolean isActivityInBackStack (Class cls) { + return runningActivities.contains(cls); + } } ``` 2. create `LaunchActivity` ```diff + public class LaunchActivity extends Activity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + BaseApplication application = (BaseApplication) getApplication(); + // check that MainActivity is not started yet + if (!application.isActivityInBackStack(MainActivity.class)) { + Intent intent = new Intent(this, MainActivity.class); + startActivity(intent); + } + finish(); + } + } ``` 3. Modify `AndroidManifest.xml` and move `android.intent.action.MAIN` and `android.intent.category.LAUNCHER` from your `.MainActivity` to `.LaunchActivity` ```diff + + + + + + ... - - - - ... ``` 4. Modify `MainActivity` to look _something_ like the following (you likely already have an `onCreate` method that you need to modify): ```java @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(null); ((BaseApplication) getApplication()).addActivityToStack(this.getClass()); } @Override protected void onDestroy() { super.onDestroy(); ((BaseApplication) getApplication()).removeActivityFromStack(this.getClass()); } ``` ## 8. How to resolve the _Failed to start this transaction, as there is an active transaction at the moment_ error? Users might encounter this error when the app moves to the background and then back to the foreground while the login/logout alert box is displayed, for example by locking and unlocking the device. The alert box would get dismissed but when the user tries to log in again, the Web Auth operation fails with the `transactionActiveAlready` error. This is a known issue with `ASWebAuthenticationSession` and it is not specific to react-native-auth0. We have already filed a bug report with Apple and are awaiting for a response from them. ### Workarounds #### Clear the login transaction when handling the `transactionActiveAlready` error You can invoke `cancelWebAuth()` to manually clear the current login transaction upon encountering this error. Then, you can retry login. For example: ```js auth0.webAuth.authorize({}).catch((error) => { if ( error.cause == 'Failed to start this transaction, as there is an active transaction at the moment ' ) auth0.webAuth.cancelWebAuth(); // retry auth logic }); ``` #### Clear the login transaction when the app moves to the background/foreground You can invoke `cancelWebAuth()` to manually clear the current login transaction when the app moves to the background or back to the foreground. However, you need to make sure to not cancel valid login attempts –for example, when the user switches briefly to another app while the login page is open. #### Avoid the login/logout alert box If you don't need SSO, consider using `ephemeral sessions` or `SFSafariViewController` instead of `ASWebAuthenticationSession`. See [2. How can I disable the iOS _login_ alert box?](#2-how-can-i-disable-the-ios-login-alert-box) for more information. ## 9. Why doesn't `await authorize()` work on the web? How do I handle login? This is a key difference between native and web platforms. - **On Native (iOS/Android):** `authorize()` opens an in-app browser overlay. Your app continues running in the background. When the user authenticates, the browser dismisses and the `authorize()` promise resolves with the credentials. `await` works as expected. - **On Web:** `authorize()` triggers a **full-page browser redirect** to the Auth0 Universal Login page. Your application's current state is lost. After authentication, the user is redirected back to your app, which causes your entire React application to reload and re-initialize from scratch. Because of this, the original `authorize()` promise is never able to resolve. **The Solution: Use the `useAuth0` Hook** The recommended way to handle this is by using the `Auth0Provider` and `useAuth0` hook. They are designed to manage this flow automatically: 1. **On initial load:** The provider checks if the user is returning from a login redirect. If so, it processes the credentials in the URL and establishes a session. 2. **State Management:** The `user` and `isLoading` properties from the `useAuth0` hook will automatically update to reflect the authenticated state after the redirect is handled. Your UI should be reactive to the `user` and `isLoading` state, rather than trying to `await` the result of `authorize()`. ```jsx import { useAuth0 } from 'react-native-auth0'; const MyComponent = () => { const { authorize, user, isLoading } = useAuth0(); // This component will re-render after the redirect, // and `user` will be populated. if (isLoading) { return Loading...; } return ( {user ? ( Welcome, {user.name}! ) : (