This guide provides usage examples specifically for developers targeting React Native Web. The web platform uses the underlying @auth0/auth0-spa-js library, and its features are aligned with browser security best practices.
This is the simplest and recommended way to integrate Auth0. The Auth0Provider handles all the complexity of the redirect flow automatically.
In your main application entry point (e.g., App.tsx), wrap your application with the provider.
// src/App.tsx
import React from 'react';
import { Auth0Provider } from 'react-native-auth0';
import config from './auth0-configuration';
import MainComponent from './MainComponent'; // Your main app UI
const App = () => (
<Auth0Provider domain={config.domain} clientId={config.clientId}>
<MainComponent />
</Auth0Provider>
);
export default App;The Auth0Provider will automatically handle the redirect callback when your app loads. The useAuth0 hook will then provide the authentication state.
// src/MainComponent.tsx
import React from 'react';
import { useAuth0 } from 'react-native-auth0';
import { View, Button, Text, ActivityIndicator } from 'react-native';
const MainComponent = () => {
const { authorize, clearSession, user, isLoading, error } = useAuth0();
const onLogin = async () => {
try {
// This triggers a redirect to the Auth0 Universal Login page.
await authorize({ scope: 'openid profile email' });
} catch (e) {
console.error('Login error:', e);
}
};
const onLogout = async () => {
try {
await clearSession();
} catch (e) {
console.error('Logout error:', e);
}
};
if (isLoading) {
return (
<View>
<ActivityIndicator size="large" />
</View>
);
}
return (
<View>
{error && <Text>Error: {error.message}</Text>}
{user ? (
<>
<Text>Welcome, {user.name}!</Text>
<Button title="Log Out" onPress={onLogout} />
</>
) : (
<Button title="Log In" onPress={onLogin} />
)}
</View>
);
};If you are not using React Hooks or need more fine-grained control, you can instantiate the Auth0 class and handle the redirect callback manually.
Create a singleton instance of the client.
// src/api/auth0.ts
import Auth0 from 'react-native-auth0';
import config from '../auth0-configuration';
const auth0 = new Auth0({
domain: config.domain,
clientId: config.clientId,
});
export default auth0;In your application's root component or entry point, you need to add logic to process the result from Auth0 after the user is redirected back.
// src/App.tsx
import React, { useEffect, useState } from 'react';
import { View, Button, Text } from 'react-native';
import auth0 from './api/auth0'; // Import your singleton
import type { User } from 'react-native-auth0';
const App = () => {
const [user, setUser] = useState<User | null>(null);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
const checkSession = async () => {
// Check if the URL contains redirect parameters
if (window.location.search.includes('code=') && window.location.search.includes('state=')) {
try {
// Process the redirect
await auth0.webAuth.handleRedirectCallback();
} catch (e) {
console.error(e);
}
// Clean the URL
window.history.replaceState({}, document.title, '/');
}
// After handling a potential redirect, check for an existing session
try {
const credentials = await auth0.credentialsManager.getCredentials();
// Assuming you have a way to decode the idToken to get the user
// const decodedUser = jwt_decode(credentials.idToken);
// setUser(decodedUser);
} catch (e) {
// No credentials, user is not logged in
setUser(null);
}
setIsLoading(false);
};
checkSession();
}, []);
const onLogin = async () => {
await auth0.webAuth.authorize({ scope: 'openid profile email' });
};
const onLogout = async () => {
await auth0.webAuth.clearSession();
};
// ... Render UI based on isLoading and user state ...
};The MFA Flexible Factors Grant is fully supported on the web platform. It uses the @auth0/auth0-spa-js MFA API under the hood.
import React, { useState } from 'react';
import { View, Button, TextInput, Text } from 'react-native';
import { useAuth0, MfaError, MfaErrorCodes } from 'react-native-auth0';
function MfaScreen({ mfaToken }: { mfaToken: string }) {
const { mfa } = useAuth0();
const [otp, setOtp] = useState('');
const listAuthenticators = async () => {
try {
const authenticators = await mfa.getAuthenticators({ mfaToken });
console.log('Authenticators:', authenticators);
} catch (error) {
if (error instanceof MfaError) {
console.error('MFA error:', error.type, error.message);
}
}
};
const enrollTotp = async () => {
try {
const challenge = await mfa.enroll({ mfaToken, factorType: 'otp' });
if (challenge.type === 'totp') {
console.log('Scan QR:', challenge.barcodeUri);
console.log('Secret:', challenge.secret);
}
} catch (error) {
if (error instanceof MfaError) {
console.error('Enrollment error:', error.type);
}
}
};
const verifyOtp = async () => {
try {
const credentials = await mfa.verify({ mfaToken, otp });
console.log('Authenticated!');
} catch (error) {
if (error instanceof MfaError) {
switch (error.type) {
case MfaErrorCodes.INVALID_OTP:
console.log('Incorrect code');
break;
case MfaErrorCodes.TOO_MANY_ATTEMPTS:
console.log('Too many attempts');
break;
case MfaErrorCodes.EXPIRED_MFA_TOKEN:
console.log('Session expired');
break;
}
}
}
};
return (
<View>
<Button title="List Authenticators" onPress={listAuthenticators} />
<Button title="Enroll TOTP" onPress={enrollTotp} />
<TextInput placeholder="Enter OTP" value={otp} onChangeText={setOtp} />
<Button title="Verify" onPress={verifyOtp} />
</View>
);
}import Auth0, { MfaError, MfaErrorCodes } from 'react-native-auth0';
const auth0 = new Auth0({
domain: 'YOUR_AUTH0_DOMAIN',
clientId: 'YOUR_AUTH0_CLIENT_ID',
});
// List authenticators
const authenticators = await auth0.mfa.getAuthenticators({
mfaToken: 'mfa_token',
});
// Enroll TOTP
const challenge = await auth0.mfa.enroll({
mfaToken: 'mfa_token',
factorType: 'otp',
});
// Enroll SMS
const smsChallenge = await auth0.mfa.enroll({
mfaToken: 'mfa_token',
factorType: 'sms',
phoneNumber: '+12025550135',
});
// Enroll push notification (Auth0 Guardian) — web returns barcodeUri + oobCode
const pushChallenge = await auth0.mfa.enroll({
mfaToken: 'mfa_token',
factorType: 'push',
});
// Challenge an authenticator
const challengeResult = await auth0.mfa.challenge({
mfaToken: 'mfa_token',
authenticatorId: 'sms|dev_123',
});
// Verify OTP
const credentials = await auth0.mfa.verify({
mfaToken: 'mfa_token',
otp: '123456',
});Passkeys are supported on web via @auth0/auth0-spa-js. The flow is the same three steps as native (challenge → WebAuthn ceremony → exchange), but step 2 uses the browser's built-in WebAuthn API (navigator.credentials.create()/.get()) instead of a native module — the app calls it directly, the SDK does not perform this step for you. getTokenByPasskey's authResponse accepts the raw PublicKeyCredential returned by navigator.credentials directly on web — no manual serialization needed (unlike native, which takes a JSON string; see Signup with Passkey (Web) in EXAMPLES.md for the full signup example).
Secure context requirement: navigator.credentials.create()/.get() only work over HTTPS (or localhost for local development). Apps served over plain HTTP will fail at the WebAuthn ceremony with a SecurityError.
Because navigator.credentials.create()/.get() require a user gesture, call passkeySignupChallenge / passkeyLoginChallenge from within a click handler (not, for example, from a useEffect).
import { useAuth0, PasskeyError } from 'react-native-auth0';
function PasskeyLoginButton() {
const { passkeyLoginChallenge, getTokenByPasskey } = useAuth0();
const handleLogin = async () => {
try {
const challenge = await passkeyLoginChallenge({
realm: 'Username-Password-Authentication',
});
// App calls navigator.credentials directly (not wrapped by SDK)
const credential = (await navigator.credentials.get({
publicKey:
challenge.authParamsPublicKey as PublicKeyCredentialRequestOptions,
})) as PublicKeyCredential | null;
if (!credential) {
// User cancelled or no credential available
throw new Error('No passkey credential returned');
}
const credentials = await getTokenByPasskey({
authSession: challenge.authSession,
authResponse: credential,
realm: 'Username-Password-Authentication',
});
console.log('Signed in with passkey');
} catch (error) {
if (error instanceof PasskeyError) {
console.error('Passkey login failed:', error.type, error.message);
// Handle MFA required scenario
const mfaPayload = error.getMfaRequiredPayload();
if (mfaPayload) {
console.log('MFA required. Token:', mfaPayload.mfaToken);
console.log('Available factors:', mfaPayload.mfaRequirements);
// Continue with mfa.challenge() and mfa.verify()
}
}
}
};
return <button onClick={handleLogin}>Sign In with Passkey</button>;
}The web platform supports direct authentication grants including auth.passwordRealm(), auth.createUser(), auth.resetPassword(), and the MFA Flexible Factors Grant. These methods make direct HTTP calls to the Auth0 API.
Token refresh is handled automatically by credentialsManager.getCredentials() on the web. The auth.refreshToken() method is not available.
The My Account API is supported on the web platform. The auth0.myAccount client works the same way as on native, so the examples in EXAMPLES.md apply. Passkey enrollment on the web uses the browser's WebAuthn APIs instead of a native passkey module.
When DPoP is enabled (the default), a My Account call on the web only succeeds when the supplied access token was issued by the same client instance, because the DPoP proof is signed with that client's keypair. When the client is not configured with DPoP, plain bearer tokens are used and any valid access token works.