> ## Documentation Index
> Fetch the complete documentation index at: https://docs-dev.auth0-mintlify.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Add Login to Your React Native Application

> This guide demonstrates how to integrate Auth0 with any React Native app using the Auth0 React Native SDK.

export const HowToSchema = () => <script type="application/ld+json">
    {'{"@context":"https://schema.org","@type":"HowTo"}'}
  </script>;

<HowToSchema />

<Tip>
  This Quickstart is for the React Native framework. To integrate Auth0 into your Expo application, refer to the [Expo Quickstart](https://auth0.com/docs/quickstart/native/react-native-expo/interactive).
</Tip>

<Accordion title="Use AI to integrate Auth0" icon="microchip-ai" iconType="solid" defaultOpen>
  If you use an AI coding assistant like Claude Code, Cursor, or GitHub Copilot, you can add Auth0 authentication automatically in minutes using [agent skills](https://agentskills.io/home).

  **Install:**

  ```bash theme={null}
  npx skills add https://github.com/auth0/agent-skills --skill auth0-react-native
  ```

  **Then ask your AI assistant:**

  ```text theme={null}
  Add Auth0 authentication to my React Native app
  ```

  Your AI assistant will automatically create your Auth0 application, fetch credentials, install `react-native-auth0`, configure native dependencies, and set up your authentication flow. [Full agent skills documentation →](/docs/quickstart/agent-skills)
</Accordion>

## Get Started

<Steps>
  <Step title="Create a new React Native project" stepNumber={1}>
    Create a new React Native project for this quickstart.

    **In your terminal:**

    ```bash theme={null}
    npx @react-native-community/cli init Auth0ReactNativeSample
    cd Auth0ReactNativeSample
    ```

    Configure your project with:

    * **Name**: `Auth0ReactNativeSample`
    * **Package name**: `com.auth0.samples.reactnative`

    <Tip>
      This creates a React Native app with the latest stable version. The Auth0 SDK requires React Native 0.78.0+ and React 19.0.0+.
    </Tip>
  </Step>

  <Step title="Install the Auth0 SDK" stepNumber={2}>
    Add the Auth0 React Native SDK to your project.

    ```bash theme={null}
    npm install react-native-auth0
    ```

    For iOS, install the native dependencies:

    ```bash theme={null}
    cd ios && pod install && cd ..
    ```

    <Tip>
      The SDK auto-links on both platforms. The `pod install` step installs the required iOS native modules (Auth0.swift, JWTDecode, SimpleKeychain).
    </Tip>
  </Step>

  <Step title="Configure your Auth0 Application" stepNumber={3}>
    Create and configure an Auth0 application to work with your React Native app.

    1. Head to the [Auth0 Dashboard](https://manage.auth0.com/dashboard/)
    2. Click on **Applications** > **Applications** > **Create Application**
    3. In the popup, enter a name for your app (e.g., `Auth0 React Native Sample`), select `Native` as the app type and click **Create**
    4. Switch to the **Settings** tab on the Application Details page
    5. Note your **Domain** and **Client ID** values

    **Allowed Callback URLs:**

    ```
    org.reactjs.native.example.auth0reactnativesample.auth0://{yourDomain}/ios/org.reactjs.native.example.auth0reactnativesample/callback,
    com.auth0reactnativesample.auth0://{yourDomain}/android/com.auth0reactnativesample/callback
    ```

    **Allowed Logout URLs:**

    ```
    org.reactjs.native.example.auth0reactnativesample.auth0://{yourDomain}/ios/org.reactjs.native.example.auth0reactnativesample/callback,
    com.auth0reactnativesample.auth0://{yourDomain}/android/com.auth0reactnativesample/callback
    ```

    Replace `{yourDomain}` with your actual Auth0 domain (e.g., `dev-abc123.us.auth0.com`).

    <Info>
      **Allowed Callback URLs** are a critical security measure to ensure users are safely returned to your application after authentication. Without a matching URL, the login process will fail, and users will be blocked by an Auth0 error page instead of accessing your app.

      **Allowed Logout URLs** are essential for providing a seamless user experience upon signing out. Without a matching URL, users will not be redirected back to your application after logout and will instead be left on a generic Auth0 page.

      The URL scheme includes `.auth0` after your bundle identifier to ensure the callback is routed to your specific app. For this quickstart, the bundle identifier is `org.reactjs.native.example.auth0reactnativesample`.
    </Info>

    <Warning>
      **Important**: The callback URL scheme must include `.auth0` after your bundle identifier (e.g., `org.reactjs.native.example.auth0reactnativesample.auth0://`). This is required for the SDK to properly handle the authentication callback.
    </Warning>
  </Step>

  <Step title="Configure Native Platforms" stepNumber={4}>
    Configure both iOS and Android to handle the authentication callback.

    **Android Configuration:**

    Open `android/app/build.gradle` and add the manifest placeholders inside `defaultConfig`:

    ```groovy android/app/build.gradle lines theme={null}
    android {
        defaultConfig {
            applicationId "com.auth0reactnativesample"
            // ... other config
            
            // Add Auth0 manifest placeholders
            manifestPlaceholders = [
                auth0Domain: "{yourDomain}",
                auth0Scheme: "${applicationId}.auth0"
            ]
        }
    }
    ```

    Replace `{yourDomain}` with your Auth0 domain (e.g., `dev-abc123.us.auth0.com`).

    **iOS Configuration:**

    <Tabs>
      <Tab title="AppDelegate.mm (Objective-C)">
        Open `ios/Auth0ReactNativeSample/AppDelegate.mm` and add the URL handling method:

        ```objc ios/Auth0ReactNativeSample/AppDelegate.mm lines theme={null}
        #import <React/RCTLinkingManager.h>

        // Add this method inside the @implementation block
        - (BOOL)application:(UIApplication *)app
                    openURL:(NSURL *)url
                    options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options
        {
          return [RCTLinkingManager application:app openURL:url options:options];
        }
        ```
      </Tab>

      <Tab title="AppDelegate.swift (Swift)">
        Open `ios/Auth0ReactNativeSample/AppDelegate.swift` and add the URL handling method:

        ```swift ios/Auth0ReactNativeSample/AppDelegate.swift lines theme={null}
        import React

        // Add this method inside the AppDelegate class
        func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
          return RCTLinkingManager.application(app, open: url, options: options)
        }
        ```
      </Tab>
    </Tabs>

    Open `ios/Auth0ReactNativeSample/Info.plist` and add the URL scheme. Add this before the closing `</dict>` tag:

    ```xml ios/Auth0ReactNativeSample/Info.plist lines theme={null}
    <key>CFBundleURLTypes</key>
    <array>
      <dict>
        <key>CFBundleTypeRole</key>
        <string>None</string>
        <key>CFBundleURLName</key>
        <string>auth0</string>
        <key>CFBundleURLSchemes</key>
        <array>
          <string>$(PRODUCT_BUNDLE_IDENTIFIER).auth0</string>
        </array>
      </dict>
    </array>
    ```

    <Info>
      The URL scheme uses your bundle identifier with `.auth0` appended. This ensures the callback is routed to your specific app after authentication completes in the browser.
    </Info>
  </Step>

  <Step title="Setup App Component" stepNumber={5}>
    Setup your main app component based on your chosen implementation approach.

    <Tabs>
      <Tab title="Hooks-based (with Provider)">
        Replace the contents of `App.tsx` and wrap your application with the `Auth0Provider` component:

        ```tsx App.tsx lines theme={null}
        import React from 'react';
        import {Auth0Provider} from 'react-native-auth0';
        import {SafeAreaView, StyleSheet} from 'react-native';
        import MainScreen from './src/MainScreen';

        const App = () => {
          return (
            <Auth0Provider
              domain="{yourDomain}"
              clientId="{yourClientId}">
              <SafeAreaView style={styles.container}>
                <MainScreen />
              </SafeAreaView>
            </Auth0Provider>
          );
        };

        const styles = StyleSheet.create({
          container: {
            flex: 1,
            backgroundColor: '#fff',
          },
        });

        export default App;
        ```

        Replace `{yourDomain}` with your Auth0 domain and `{yourClientId}` with your Client ID from the Auth0 Dashboard.

        <Tip>
          The `Auth0Provider` initializes the SDK and provides authentication context to all child components via the `useAuth0` hook.
        </Tip>
      </Tab>

      <Tab title="Class-based (without Provider)">
        Replace the contents of `App.tsx` with a simple container for your class-based component:

        ```tsx App.tsx lines theme={null}
        import React from 'react';
        import {SafeAreaView, StyleSheet} from 'react-native';
        import MainScreen from './src/MainScreen';

        const App = () => {
          return (
            <SafeAreaView style={styles.container}>
              <MainScreen />
            </SafeAreaView>
          );
        };

        const styles = StyleSheet.create({
          container: {
            flex: 1,
            backgroundColor: '#fff',
          },
        });

        export default App;
        ```

        <Tip>
          The class-based approach doesn't require the `Auth0Provider` since it uses the `Auth0` class instance directly. The Auth0 configuration will be in the MainScreen component.
        </Tip>
      </Tab>
    </Tabs>
  </Step>

  <Step title="Implement Login and Logout" stepNumber={6}>
    Create a screen component that handles login and logout. You can choose between a hooks-based approach (recommended) or a class-based approach.

    <Tabs>
      <Tab title="Hooks-based (Recommended)">
        Create `src/MainScreen.tsx` using the `useAuth0` hook:

        ```tsx src/MainScreen.tsx lines theme={null}
        import React from 'react';
        import {
          View,
          Text,
          Button,
          StyleSheet,
          ActivityIndicator,
          Image,
        } from 'react-native';
        import {useAuth0} from 'react-native-auth0';

        const MainScreen = () => {
          const {authorize, clearSession, user, isLoading} = useAuth0();

          const login = async () => {
            try {
              await authorize({scope: 'openid profile email'});
            } catch (e) {
              console.error(e);
            }
          };

          const logout = async () => {
            try {
              await clearSession();
            } catch (e) {
              console.error(e);
            }
          };

          if (isLoading) {
            return (
              <View style={styles.container}>
                <ActivityIndicator size="large" color="#0066cc" />
                <Text style={styles.loadingText}>Loading...</Text>
              </View>
            );
          }

          return (
            <View style={styles.container}>
              <Text style={styles.title}>Auth0 React Native</Text>

              {user ? (
                <View style={styles.profileContainer}>
                  {user.picture && (
                    <Image source={{uri: user.picture}} style={styles.avatar} />
                  )}
                  <Text style={styles.welcomeText}>Welcome, {user.name}!</Text>
                  <Text style={styles.emailText}>{user.email}</Text>
                  <View style={styles.buttonContainer}>
                    <Button title="Log Out" onPress={logout} color="#dc3545" />
                  </View>
                </View>
              ) : (
                <View style={styles.loginContainer}>
                  <Text style={styles.subtitle}>
                    Tap the button below to log in
                  </Text>
                  <View style={styles.buttonContainer}>
                    <Button title="Log In" onPress={login} color="#0066cc" />
                  </View>
                </View>
              )}
            </View>
          );
        };

        const styles = StyleSheet.create({
          container: {
            flex: 1,
            justifyContent: 'center',
            alignItems: 'center',
            padding: 20,
          },
          title: {
            fontSize: 28,
            fontWeight: 'bold',
            marginBottom: 20,
            color: '#333',
          },
          subtitle: {
            fontSize: 16,
            color: '#666',
            marginBottom: 30,
            textAlign: 'center',
          },
          loadingText: {
            marginTop: 10,
            fontSize: 16,
            color: '#666',
          },
          profileContainer: {
            alignItems: 'center',
          },
          avatar: {
            width: 100,
            height: 100,
            borderRadius: 50,
            marginBottom: 20,
          },
          welcomeText: {
            fontSize: 22,
            fontWeight: '600',
            marginBottom: 8,
            color: '#333',
          },
          emailText: {
            fontSize: 16,
            color: '#666',
            marginBottom: 30,
          },
          loginContainer: {
            alignItems: 'center',
          },
          buttonContainer: {
            width: 200,
            marginTop: 10,
          },
        });

        export default MainScreen;
        ```
      </Tab>

      <Tab title="Class-based">
        Create `src/MainScreen.tsx` using the `Auth0` class directly:

        ```tsx src/MainScreen.tsx lines theme={null}
        import React, {Component} from 'react';
        import {
          View,
          Text,
          Button,
          StyleSheet,
          ActivityIndicator,
          Image,
        } from 'react-native';
        import Auth0, {Credentials} from 'react-native-auth0';

        const auth0 = new Auth0({
          domain: '{yourDomain}',
          clientId: '{yourClientId}',
        });

        interface User {
          name?: string;
          email?: string;
          picture?: string;
        }

        interface MainScreenState {
          user: User | null;
          isLoading: boolean;
        }

        class MainScreen extends Component<{}, MainScreenState> {
          constructor(props: {}) {
            super(props);
            this.state = {
              user: null,
              isLoading: true,
            };
          }

          async componentDidMount() {
            await this.checkAuthStatus();
          }

          checkAuthStatus = async () => {
            try {
              const hasValidCredentials = await auth0.credentialsManager.hasValidCredentials();
              if (hasValidCredentials) {
                const credentials = await auth0.credentialsManager.getCredentials();
                const userInfo = await auth0.auth.userInfo({token: credentials.accessToken});
                this.setState({user: userInfo, isLoading: false});
              } else {
                this.setState({isLoading: false});
              }
            } catch (e) {
              console.error(e);
              this.setState({isLoading: false});
            }
          };

          login = async () => {
            try {
              const credentials: Credentials = await auth0.webAuth.authorize({
                scope: 'openid profile email',
              });
              
              await auth0.credentialsManager.saveCredentials(credentials);
              const userInfo = await auth0.auth.userInfo({token: credentials.accessToken});
              this.setState({user: userInfo});
            } catch (e) {
              console.error(e);
            }
          };

          logout = async () => {
            try {
              await auth0.webAuth.clearSession();
              await auth0.credentialsManager.clearCredentials();
              this.setState({user: null});
            } catch (e) {
              console.error(e);
            }
          };

          render() {
            const {user, isLoading} = this.state;

            if (isLoading) {
              return (
                <View style={styles.container}>
                  <ActivityIndicator size="large" color="#0066cc" />
                  <Text style={styles.loadingText}>Loading...</Text>
                </View>
              );
            }

            return (
              <View style={styles.container}>
                <Text style={styles.title}>Auth0 React Native</Text>

                {user ? (
                  <View style={styles.profileContainer}>
                    {user.picture && (
                      <Image source={{uri: user.picture}} style={styles.avatar} />
                    )}
                    <Text style={styles.welcomeText}>Welcome, {user.name}!</Text>
                    <Text style={styles.emailText}>{user.email}</Text>
                    <View style={styles.buttonContainer}>
                      <Button title="Log Out" onPress={this.logout} color="#dc3545" />
                    </View>
                  </View>
                ) : (
                  <View style={styles.loginContainer}>
                    <Text style={styles.subtitle}>
                      Tap the button below to log in
                    </Text>
                    <View style={styles.buttonContainer}>
                      <Button title="Log In" onPress={this.login} color="#0066cc" />
                    </View>
                  </View>
                )}
              </View>
            );
          }
        }

        const styles = StyleSheet.create({
          container: {
            flex: 1,
            justifyContent: 'center',
            alignItems: 'center',
            padding: 20,
          },
          title: {
            fontSize: 28,
            fontWeight: 'bold',
            marginBottom: 20,
            color: '#333',
          },
          subtitle: {
            fontSize: 16,
            color: '#666',
            marginBottom: 30,
            textAlign: 'center',
          },
          loadingText: {
            marginTop: 10,
            fontSize: 16,
            color: '#666',
          },
          profileContainer: {
            alignItems: 'center',
          },
          avatar: {
            width: 100,
            height: 100,
            borderRadius: 50,
            marginBottom: 20,
          },
          welcomeText: {
            fontSize: 22,
            fontWeight: '600',
            marginBottom: 8,
            color: '#333',
          },
          emailText: {
            fontSize: 16,
            color: '#666',
            marginBottom: 30,
          },
          loginContainer: {
            alignItems: 'center',
          },
          buttonContainer: {
            width: 200,
            marginTop: 10,
          },
        });

        export default MainScreen;
        ```

        Replace `{yourDomain}` with your Auth0 domain and `{yourClientId}` with your Client ID from the Auth0 Dashboard.
      </Tab>
    </Tabs>

    <Info>
      The `authorize()` method (hooks) or `auth0.webAuth.authorize()` (class) opens Auth0's Universal Login in a secure browser (ASWebAuthenticationSession on iOS, Chrome Custom Tabs on Android). The `clearSession()` method logs the user out and clears both the browser session and stored credentials.
    </Info>
  </Step>

  <Step title="Run your app" stepNumber={7}>
    Build and run your React Native application on a device or emulator.

    **For iOS (requires macOS):**

    ```bash theme={null}
    npx react-native run-ios
    ```

    **For Android:**

    ```bash theme={null}
    npx react-native run-android
    ```

    **Expected flow:**

    1. App launches showing "Log In" button
    2. Tap **Log In** → Browser opens with Auth0 Universal Login
    3. Complete login (sign up or sign in)
    4. Browser closes → Returns to app automatically
    5. User profile displays with name, email, and avatar

    <Warning>
      iOS Simulator requires a valid Apple Developer account for ASWebAuthenticationSession. For testing on simulator without an account, use a physical device or Android emulator instead.
    </Warning>
  </Step>
</Steps>

<Check>
  **Checkpoint**

  You should now have a fully functional Auth0 login experience running on your device or emulator. The app uses secure browser authentication and automatically manages credentials.
</Check>

***

## Troubleshooting & Advanced

<Accordion title="Common Issues & Solutions">
  ### "Callback URL mismatch" error

  **Solution:**

  1. Verify the exact URL (including `.auth0` suffix) is in **Allowed Callback URLs** in your Auth0 Dashboard
  2. Ensure both iOS and Android URLs are added
  3. Check that `{yourDomain}` is replaced with your actual Auth0 domain

  ### App doesn't return after login (iOS)

  **Fix:**

  1. Check `Info.plist` has the `CFBundleURLSchemes` entry with `$(PRODUCT_BUNDLE_IDENTIFIER).auth0`
  2. Verify `AppDelegate.mm` includes the URL handling method
  3. Ensure the URL scheme matches your bundle identifier

  ### Android build fails

  **Fix:**

  1. Add `auth0Domain` and `auth0Scheme` manifest placeholders to `build.gradle`
  2. Sync project with Gradle files
  3. Clean build: `./gradlew clean`

  ### "PKCE not allowed" error

  **Fix:**

  1. Go to Auth0 Dashboard → Applications → Your Application
  2. Change application type to **Native**
  3. Save changes and try again

  ### Pod install fails (iOS)

  **Fix:**

  1. Update CocoaPods: `sudo gem install cocoapods`
  2. Update pod repo: `pod install --repo-update`
  3. If issues persist, delete `Podfile.lock` and `ios/Pods` folder, then run `pod install` again

  ### User cancelled error

  Handle gracefully in your login function:

  ```tsx expandable theme={null}
  const login = async () => {
    try {
      await authorize({scope: 'openid profile email'});
    } catch (e) {
      if (e.message === 'a0.session.user_cancelled') {
        // User closed login screen - handle gracefully
        console.log('Login cancelled by user');
      } else {
        console.error('Login failed:', e);
      }
    }
  };
  ```

  ### iOS Alert Dialog

  On iOS, users see a permission dialog: *"App Name" Wants to Use "auth0.com" to Sign In*. This is expected behavior from `ASWebAuthenticationSession`. Users must tap **Continue** to proceed.

  To customize this behavior, you can use ephemeral sessions (disables SSO):

  ```tsx theme={null}
  await authorize({scope: 'openid profile email'}, {ephemeralSession: true});
  ```
</Accordion>

<Accordion title="Retrieving Access Tokens">
  Use the `getCredentials()` method to retrieve tokens for API calls:

  ```tsx expandable lines theme={null}
  import {useAuth0} from 'react-native-auth0';

  const MyComponent = () => {
    const {getCredentials} = useAuth0();

    const callApi = async () => {
      try {
        const credentials = await getCredentials();
        const response = await fetch('https://your-api.com/endpoint', {
          headers: {
            Authorization: `Bearer ${credentials.accessToken}`,
          },
        });
        // Handle response
      } catch (e) {
        console.error('Failed to get credentials', e);
      }
    };
  };
  ```

  <Tip>
    Include the `offline_access` scope during login to receive a refresh token: `authorize({scope: 'openid profile email offline_access'})`. This enables automatic token renewal.
  </Tip>
</Accordion>

<Accordion title="Check Authentication Status on App Launch">
  Use `hasValidCredentials()` to check if the user is already logged in:

  ```tsx expandable lines theme={null}
  import {useAuth0} from 'react-native-auth0';
  import {useEffect} from 'react';

  const App = () => {
    const {hasValidCredentials, getCredentials} = useAuth0();

    useEffect(() => {
      const checkAuth = async () => {
        const isLoggedIn = await hasValidCredentials();
        if (isLoggedIn) {
          const credentials = await getCredentials();
          // User is authenticated, load their data
        }
      };
      checkAuth();
    }, []);
  };
  ```
</Accordion>

<Accordion title="Production Deployment">
  ### Before deploying to production

  **Use HTTPS callback URLs** for enhanced security:

  ```text theme={null}
  https://{yourDomain}/ios/{bundleId}/callback
  https://{yourDomain}/android/{packageName}/callback
  ```

  **Configure Android App Links** in Auth0 Dashboard:

  * Settings → Advanced Settings → Device Settings
  * Add your app's SHA-256 fingerprint

  **Configure iOS Universal Links:**

  * Add Associated Domains capability in Xcode
  * Add `webcredentials:{yourDomain}` to Associated Domains

  **Enable biometric authentication** for sensitive apps using `localAuthenticationOptions` in `Auth0Provider`

  **Review security settings** in Auth0 Dashboard:

  * Enable **OIDC Conformant** in Advanced Settings
  * Configure **Token Expiration** appropriately
  * Set up **Brute Force Protection**
  * Test on multiple devices and OS versions
  * Implement proper error handling for network failures
</Accordion>

* [Sample Application](https://github.com/auth0-samples/auth0-react-native-sample)
* [Migration Guide (v4 to v5)](https://github.com/auth0/react-native-auth0/blob/master/MIGRATION_GUIDE.md)
