# How to Use AuthView in an Expo App: Native Authentication with Clerk - Part 2

> Part 2 of 2. Start with [How to Use AuthView in an Expo App: Native Authentication with Clerk](https://clerk.com/articles/how-to-use-authview-in-an-expo-app-native-authentication-with-clerk.md).

This is the second part of a two-part series on building a native authentication flow in an Expo app with Clerk's AuthView component. In [Part 1](https://clerk.com/articles/how-to-use-authview-in-an-expo-app-native-authentication-with-clerk.md), you set up the Clerk application, initialized the Expo project, and built the sign-in screen plus a starter home screen. In this part, you will make the home screen state-aware, add a protected profile route with user profile management via `UserButton` and `UserProfileView`, handle authentication state, and learn how to troubleshoot common issues.

## Building the home screen

The home screen is public: it renders for signed-out visitors as well as signed-in users, and changes its content based on who is looking. Only the profile route is gated, which you set up in the next section. Keeping the landing screen reachable and guarding just the routes that need a session is the pattern to reach for in most apps.

Replace the starter `src/app/index.tsx` from Part 1 with the following:

```tsx
import { Show, useUser } from '@clerk/expo'
import { Link } from 'expo-router'
import { View, Text, StyleSheet } from 'react-native'

export default function HomeScreen() {
  const { user } = useUser()

  return (
    <View style={styles.container}>
      <Show when="signed-in">
        <Text style={styles.title}>
          Welcome, {user?.firstName || user?.primaryEmailAddress?.emailAddress}!
        </Text>
        <Text style={styles.subtitle}>You are signed in.</Text>
        <Link href="/(protected)/profile" style={styles.link}>
          <Text style={styles.linkText}>View Profile</Text>
        </Link>
      </Show>

      <Show when="signed-out">
        <Text style={styles.title}>Welcome to Clerk + Expo</Text>
        <Text style={styles.subtitle}>Sign in to get started.</Text>
        <Link href="/(auth)/sign-in" style={styles.link}>
          <Text style={styles.linkText}>Sign In</Text>
        </Link>
      </Show>
    </View>
  )
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    padding: 20,
  },
  title: {
    fontSize: 24,
    fontWeight: 'bold',
    marginBottom: 8,
  },
  subtitle: {
    fontSize: 16,
    color: '#666',
    marginBottom: 20,
  },
  link: {
    padding: 12,
  },
  linkText: {
    fontSize: 16,
    color: '#6C47FF',
    fontWeight: '600',
  },
})
```

The `Show` component is Clerk's Core 3 replacement for the older `SignedIn` and `SignedOut` components. It conditionally renders content based on authentication state:

- **`<Show when="signed-in">`** — content is visible only when the user is authenticated
- **`<Show when="signed-out">`** — content is visible only when the user is not authenticated

The `Show` component only controls _visibility_ — it is not a security boundary. Sensitive data must always be verified server-side. It supports a `fallback` prop for loading states and is preferred over manual `isSignedIn` conditional rendering for cleaner JSX.

The `useUser()` hook provides access to the current user's data, including `firstName`, `lastName`, `primaryEmailAddress`, and `imageUrl`.

**Checkpoint:** The home screen should show different content based on authentication state. Signed-in users see a welcome message; signed-out users see a sign-in prompt.

## Adding the user profile page

### Create the protected route group

The profile screen needs a session, so it goes in a `(protected)` route group with a layout that turns signed-out visitors away. Create `src/app/(protected)/_layout.tsx`:

```tsx
import { useAuth } from '@clerk/expo'
import { Redirect, Slot } from 'expo-router'
import { View, Text, StyleSheet } from 'react-native'

export default function ProtectedLayout() {
  const { isSignedIn, isLoaded } = useAuth()

  if (!isLoaded) {
    return (
      <View style={styles.loading}>
        <Text>Loading...</Text>
      </View>
    )
  }

  if (!isSignedIn) {
    return <Redirect href="/(auth)/sign-in" />
  }

  return <Slot />
}

const styles = StyleSheet.create({
  loading: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
})
```

This mirrors the auth layout from Part 1, in the opposite direction. The auth layout redirects _signed-in_ users away from the sign-in screen; this layout redirects _signed-out_ users to it. The `isLoaded` check shows a loading indicator while Clerk determines the authentication state, so no redirect fires before the answer is known.

Because the guard lives in the layout, every route you add to `(protected)` inherits it — you never repeat the check in individual screens.

### Build the profile screen

Create `src/app/(protected)/profile.tsx`. This screen demonstrates two more native components: `UserButton` and `UserProfileView`.

```tsx
import { useAuth, useUser } from '@clerk/expo'
import { UserButton, UserProfileView } from '@clerk/expo/native'
import { View, Text, Pressable, StyleSheet, ScrollView } from 'react-native'

export default function ProfileScreen() {
  const { user } = useUser()
  const { signOut } = useAuth()

  const handleSignOut = async () => {
    await signOut()
  }

  return (
    <ScrollView contentContainerStyle={styles.container}>
      <View style={styles.header}>
        <View style={styles.avatarContainer}>
          <UserButton />
        </View>
        <Text style={styles.name}>{user?.fullName}</Text>
        <Text style={styles.email}>{user?.primaryEmailAddress?.emailAddress}</Text>
      </View>

      <View style={styles.profileSection}>
        <Text style={styles.sectionTitle}>Profile Settings</Text>
        <UserProfileView />
      </View>

      <Pressable onPress={handleSignOut} style={styles.signOutButton}>
        <Text style={styles.signOutText}>Sign Out</Text>
      </Pressable>
    </ScrollView>
  )
}

const styles = StyleSheet.create({
  container: {
    flexGrow: 1,
    padding: 20,
  },
  header: {
    alignItems: 'center',
    marginBottom: 24,
    marginTop: 40,
  },
  avatarContainer: {
    marginBottom: 12,
  },
  name: {
    fontSize: 22,
    fontWeight: 'bold',
  },
  email: {
    fontSize: 14,
    color: '#666',
    marginTop: 4,
  },
  profileSection: {
    flex: 1,
    marginBottom: 24,
  },
  sectionTitle: {
    fontSize: 18,
    fontWeight: '600',
    marginBottom: 12,
  },
  signOutButton: {
    backgroundColor: '#FF3B30',
    padding: 16,
    borderRadius: 8,
    alignItems: 'center',
    marginBottom: 40,
  },
  signOutText: {
    color: '#fff',
    fontSize: 16,
    fontWeight: '600',
  },
})
```

### The UserButton component

`UserButton` renders a circular avatar showing the user's profile image or initials. Tapping it opens a native profile management modal that includes account settings and sign-out functionality. The modal sign-out automatically syncs with the JavaScript SDK.

`UserButton` takes no props and renders the native avatar button at its default platform size. It does not stretch to fill its parent, so wrap it in a `View` when you need to position it or add spacing — in this example, the `avatarContainer` style adds spacing below the button in the header.

### The UserProfileView component

`UserProfileView` renders Clerk's native profile-management UI directly in your screen. The `@clerk/expo/native` entry point exports exactly three components — `AuthView`, `UserButton`, and `UserProfileView` — so there are two ways to show profile management:

1. **Tap `UserButton`** — tapping the avatar opens the platform-native user profile surface. This is the simplest approach and is what this tutorial uses in the header.
2. **Render `UserProfileView` yourself** — embed it inline in a screen or route (as the profile page does above), or place it inside your own React Native `Modal` or bottom sheet when you want to present it as an overlay.

This tutorial uses both: `UserButton` opens the native profile surface when tapped, and `UserProfileView` renders inline for a dedicated profile settings section.

`UserProfileView` accepts three props:

- `isDismissible` — a boolean (default `true`) that controls the native view's built-in dismiss button. It does **not** present a modal on its own; it only toggles that dismiss affordance.
- `style` — a standard React Native style applied to the container (for example, `style={{ flex: 1 }}` to fill the available space).
- `onDismiss` — a callback that fires when the user dismisses the native view.

When you embed `UserProfileView` inline, as in this tutorial, the defaults are correct and no props are required. When you wrap it in your own `Modal` or sheet, set `isDismissible={false}` so your presentation layer — not the native view — owns dismissal, and use `onDismiss` to close your overlay.

> There is no `useUserProfileModal()` hook in `@clerk/expo`. To present the profile as a modal, render `UserProfileView` inside your own `Modal`, sheet, or route rather than calling a hook. Sign-out performed inside `UserProfileView` is detected automatically and synced with the JavaScript SDK.

### Display user information and sign-out

The `useUser()` hook provides the current user's profile data:

- `user.fullName` — the user's full name
- `user.firstName` — the user's first name
- `user.primaryEmailAddress.emailAddress` — the user's primary email
- `user.imageUrl` — the user's profile image URL

For sign-out, `UserButton` and `UserProfileView` both include built-in sign-out functionality that syncs with the JavaScript SDK automatically. The custom sign-out button in this example uses `useAuth().signOut()` for demonstration — it calls `signOut()`, and the `(protected)` layout's auth guard then detects that `isSignedIn` is `false` and redirects to the sign-in screen. No explicit navigation call is needed in the handler.

**Checkpoint:** The profile page should display a UserButton avatar, inline profile settings via UserProfileView, and user information. Tapping UserButton opens the native profile modal. The sign-out flow works correctly.

## Handling authentication state and navigation

### Session synchronization explained

When using native components, authentication happens in the native layer (SwiftUI/Jetpack Compose) before the JavaScript SDK is aware of it. Understanding this synchronization is important for avoiding common issues.

The synchronization flow:

1. The user authenticates through the native AuthView UI
2. The native SDK (`clerk-ios` or `clerk-android`) creates a session with Clerk's backend
3. `@clerk/expo` detects the native session and syncs it to the JavaScript SDK
4. React hooks (`useAuth`, `useUser`, `useSession`) update with the new state

Session tokens have a 60-second lifetime and are refreshed proactively at the 50-second mark. This means the JavaScript SDK always has a current token available for API calls. The `tokenCache` using `expo-secure-store` persists the session across app restarts — users do not need to re-authenticate unless the session is explicitly ended.

The `treatPendingAsSignedOut: false` option is critical when using native components. During the brief synchronization window between native authentication and JavaScript SDK state, auth status is "pending." Without this flag, `isSignedIn` defaults to `false` during the pending state, which triggers redirect logic prematurely. This flag is only needed in components where native authentication is actively happening — in route guard layouts like the `(protected)` layout, the default behavior is correct.

### Protected route patterns

This tutorial uses a consistent pattern for protecting routes:

- **Auth layout** (`(auth)/_layout.tsx`) — redirects signed-in users away from auth screens using `<Redirect>`
- **Protected layout** (`(protected)/_layout.tsx`) — redirects signed-out users to the sign-in screen using `<Redirect>`
- Both layouts check `isLoaded` before making redirect decisions to avoid premature navigation
- The root layout contains only `ClerkProvider` and `<Slot />` — no auth logic
- `index.tsx` sits outside both groups, so the home screen stays public and uses `Show` to vary its content

> Expo Router v5 (SDK 53+) introduced [`Stack.Protected`](https://docs.expo.dev/router/advanced/protected/) as a declarative alternative to `<Redirect>`. Its `guard` prop is reactive — when the boolean changes, Expo Router redirects automatically and removes protected screens from history — so it works with Clerk once you gate rendering on `isLoaded`. This tutorial uses the `<Redirect>` pattern because it matches Clerk's official native component examples and keeps the loading state explicit, but `Stack.Protected` is a valid alternative.

### Sign-out flow

There are two ways to handle sign-out:

1. **Built-in** — `UserButton` and `UserProfileView` include sign-out functionality that automatically syncs with the JavaScript SDK. No additional code is needed.
2. **Programmatic** — call `signOut()` from the `useAuth()` hook for a custom sign-out button:

```tsx
const { signOut } = useAuth()

const handleSignOut = async () => {
  await signOut()
}
```

After sign-out, the `(protected)` layout's auth guard detects that `isSignedIn` is `false` and redirects to the sign-in screen automatically. Let the route guard react to the auth-state change rather than calling `router.replace()` in the handler: an imperative redirect here would only duplicate the guard, since the profile screen unmounts the moment the guard re-renders.

## Customization and configuration

### Configuring authentication methods

AuthView supports every authentication method that Clerk offers. Configure them in the [Clerk Dashboard](https://dashboard.clerk.com) — no code changes needed:

- Email and password
- Email verification codes
- Social providers (Google, Apple, GitHub, and more)
- Passkeys (requires additional setup — see the [Clerk passkeys guide](https://clerk.com/docs/reference/expo/passkeys.md))
- Multi-factor authentication

When you enable or disable a method in the Dashboard, AuthView reflects the change immediately in your app. This means you can add new authentication methods to a production app without shipping an app update. The exception is native Google and Apple Sign-In, which require one-time platform setup (OAuth credentials, native application registration, and a rebuild) before they work — see the troubleshooting section below.

### Handling OAuth providers with AuthView

Unlike the custom flow approach, AuthView handles Google and Apple Sign-In automatically. This is a significant developer experience advantage.

With custom flows, Google Sign-In on Android requires `expo-crypto` for nonce generation and the `useSignInWithGoogle` hook with manual session activation. Apple Sign-In requires `expo-apple-authentication`, `expo-crypto`, and the `useSignInWithApple` hook. Each provider adds roughly 25 or more lines of code.

AuthView eliminates all of this. Google Sign-In uses the Credential Manager API on Android — fully native — and a secure system browser (`ASWebAuthenticationSession`) on iOS. Apple Sign-In uses the native Sign in with Apple API (`ASAuthorization`). All OAuth state management, token exchange, and error handling happens internally.

The fully native iOS Google flow is opt-in: set `EXPO_PUBLIC_CLERK_GOOGLE_IOS_URL_SCHEME` and add the `@clerk/expo-google-signin` config plugin, which registers the URL scheme. As of `@clerk/expo` 4, that native Google module lives in its own package so apps that do not use it skip the dependency during prebuild.

### Theming and appearance

AuthView renders using native platform styling:

- On iOS, it uses SwiftUI and follows iOS design conventions
- On Android, it uses Jetpack Compose and follows Material Design patterns
- Both platforms support system light and dark mode automatically

To customize beyond system light and dark mode, point the `@clerk/expo` config plugin at a JSON theme file (see the [theming reference](https://clerk.com/docs/reference/expo/native-components/theming.md)). Semantic color tokens, a dark-mode palette, and border radius apply to all native components on both platforms; a custom `fontFamily` is currently iOS-only, and Android keeps the system font:

```json
{
  "expo": {
    "plugins": [["@clerk/expo", { "theme": "./clerk-theme.json" }]]
  }
}
```

Deeper native-level theming through `ClerkTheme` is also available at the Swift and Kotlin layer ([iOS theming](https://clerk.com/docs/ios/guides/customizing-clerk/clerk-theme.md), [Android theming](https://clerk.com/docs/android/guides/customizing-clerk/clerk-theme.md)). Theming is not exposed through React Native JavaScript props. For web components (`@clerk/expo/web`), the `appearance` prop and themes from `@clerk/ui` are available — these do not apply to native AuthView.

## Common issues and troubleshooting

### "Native module not available" errors

**Cause:** running the app in Expo Go instead of a development build.

**Fix:** use `npx expo run:ios` or `npx expo run:android` to create a development build. AuthView requires native modules (SwiftUI/Jetpack Compose) that Expo Go cannot provide.

### OAuth configuration errors

Common causes of OAuth failures:

- **Missing credentials** — Google or Apple Sign-In is not configured in the Clerk Dashboard
- **Incorrect Bundle ID or Team ID** — for Apple Sign-In, the Bundle ID and Team ID in the Clerk Dashboard must match your app's configuration
- **Missing SHA-1 fingerprint** — for Google Sign-In on Android, the SHA-1 certificate fingerprint must be registered
- **Missing iOS URL scheme** — only needed for the opt-in native iOS Google flow. Registering it requires the `@clerk/expo-google-signin` plugin in your `app.json` alongside `@clerk/expo`, plus `EXPO_PUBLIC_CLERK_GOOGLE_IOS_URL_SCHEME`. Before `@clerk/expo` 4, the `@clerk/expo` plugin handled this itself

### Session not syncing after sign-in

**Cause:** missing `treatPendingAsSignedOut: false` on the `useAuth()` call in your auth screen.

**Symptoms:** redirect loops after successful native authentication, or the user appears signed out immediately after signing in.

**Fix:** pass `{ treatPendingAsSignedOut: false }` to `useAuth()` in any component that uses AuthView:

```tsx
const { isSignedIn } = useAuth({ treatPendingAsSignedOut: false })
```

This flag only needs to be set in components where native authentication is actively happening. In route guard layouts (like the `(protected)` layout), the default `treatPendingAsSignedOut: true` is correct.

### Runtime error handling

AuthView handles all runtime errors automatically — this is a key advantage over building custom flows.

- **Field-level validation errors** (wrong password, invalid email, identifier not found) appear as inline error messages below the relevant input field
- **General errors** (network failures, server errors) display in a native modal sheet with a warning icon and description
- **Rate limiting** for verification codes is enforced with a visible 30-second cooldown timer
- **Haptic feedback** (iOS) triggers on field errors for tactile feedback

No error callbacks or error props are exposed to React Native. AuthView is intentionally opaque for error handling. If you need custom error handling (for logging or analytics), use custom sign-in flows with the `useSignIn` and `useSignUp` hooks instead.

### Development build caching issues

If you encounter unexpected behavior after installing or removing packages, clear the Metro bundler cache:

```bash
npx expo start --clear
```

For a complete rebuild, delete the native directories and rebuild:

```bash
rm -rf ios android && npx expo run:ios
```

## Comparing authentication approaches in Expo

Clerk offers three approaches for authentication in Expo apps. Each has different tradeoffs.

| Feature         |     AuthView (Native)     |       Custom Flows      |       Web Components      |
| --------------- | :-----------------------: | :---------------------: | :-----------------------: |
| UI rendering    | SwiftUI / Jetpack Compose |       React Native      | React DOM (Expo web only) |
| Code required   |         \~5 lines         |  25+ lines per provider |         \~5 lines         |
| Expo Go support |             No            |           Yes           |          Web only         |
| OAuth handling  |  Automatic (native APIs)  | Manual hooks + packages |    Automatic (browser)    |
| Platform feel   |        Fully native       |      Custom styled      |          Web-like         |
| MFA support     |            Yes            |          Manual         |            Yes            |
| Passkey support |            Yes            |      Extra package      |            N/A            |
| Customization   |      Dashboard config     |       Full control      |  Theme + appearance prop  |
| Error handling  |         Automatic         |          Manual         |         Automatic         |
| Status          |            Beta           |          Stable         |           Stable          |

### Manual approach vs. streamlined approach

The following comparison shows the difference between a browser-based OAuth flow and the AuthView approach for the same result.

**Manual approach — browser-based OAuth with custom hooks:**

```tsx
import * as AuthSession from 'expo-auth-session'
import * as WebBrowser from 'expo-web-browser'
import { useSSO } from '@clerk/expo'
import { View, Pressable, Text } from 'react-native'

WebBrowser.maybeCompleteAuthSession()

export default function SignInScreen() {
  const { startSSOFlow } = useSSO()

  const handleGoogleSignIn = async () => {
    try {
      const { createdSessionId, setActive } = await startSSOFlow({
        strategy: 'oauth_google',
        redirectUrl: AuthSession.makeRedirectUri(),
      })
      if (createdSessionId) {
        await setActive!({ session: createdSessionId })
      }
    } catch (err) {
      console.error('OAuth error:', err)
    }
  }

  // Repeat for Apple, GitHub, and every other provider...
  return (
    <View>
      <Pressable onPress={handleGoogleSignIn}>
        <Text>Sign in with Google</Text>
      </Pressable>
    </View>
  )
}
```

This approach is functionally correct — `expo-web-browser` uses system browsers (ASWebAuthenticationSession on iOS, Chrome Custom Tabs on Android) per [RFC 8252](https://datatracker.ietf.org/doc/html/rfc8252) recommendations. However, it requires extra packages (`expo-auth-session`, `expo-web-browser`), manual error handling, and duplicated code for every OAuth provider.

**Streamlined approach — AuthView handles everything:**

```tsx
import { useAuth } from '@clerk/expo'
import { AuthView } from '@clerk/expo/native'
import { useRouter } from 'expo-router'
import { useEffect } from 'react'
import { View } from 'react-native'

export default function SignInScreen() {
  const { isSignedIn } = useAuth({ treatPendingAsSignedOut: false })
  const router = useRouter()

  useEffect(() => {
    if (isSignedIn) {
      router.replace('/')
    }
  }, [isSignedIn])

  return (
    <View style={{ flex: 1 }}>
      <AuthView />
    </View>
  )
}
```

The same result — sign-in, sign-up, Google, Apple, MFA, passkeys, error handling — with no extra packages and no manual provider logic.

### When to use each approach

- **AuthView** — recommended for most apps. Minimal code, native UX, automatic support for all authentication methods. Use this unless you have a specific reason not to.
- **Custom flows** — when you need completely custom UI design, must support Expo Go, or need full control over every authentication step.
- **Web components** — for the Expo web platform only. They are Clerk's React DOM components re-exported through `@clerk/expo/web` and throw an error in native environments.

## Why Clerk for Expo authentication

### Developer experience advantages

AuthView eliminates hundreds of lines of custom authentication code. A single component handles sign-in, sign-up, OAuth, MFA, passkey, and password recovery flows. New authentication methods are added through Dashboard configuration — no code changes or app updates required.

The native SDK synchronization is handled transparently. Developers do not need to manage token exchange, session creation, or state synchronization between native and JavaScript layers. Secure token storage through `expo-secure-store` uses hardware-backed encryption (iOS Keychain and Android Keystore) without any configuration beyond including `tokenCache` in the `ClerkProvider`.

As of April 2026, Clerk is the only major authentication provider that ships official, first-party native UI components for Expo. Firebase Auth (`@react-native-firebase/auth`) provides API-only access with no pre-built UI — developers must build every login screen from scratch. Supabase Auth offers `@supabase/auth-ui-react` for web React, but has no React Native equivalent. Auth0 relies on browser-based OAuth through `react-native-auth0`. Clerk's `@clerk/expo` package includes AuthView, UserButton, and UserProfileView as native components, plus a config plugin that wires up the native SDKs and the Apple Sign-In entitlement (native Google Sign-In adds the optional `@clerk/expo-google-signin` package).

### Production readiness

Clerk is [SOC 2 Type 2 and HIPAA certified](https://clerk.com/changelog/2022-05-06.md), and supports GDPR and CCPA compliance. Session tokens use a 60-second lifetime with proactive refresh, minimizing the window for token misuse.

The [free tier](https://clerk.com/pricing) includes 50,000 monthly retained users per app, making it accessible for apps at any stage of development.

## Conclusion

You have now completed the integration of Clerk's native authentication components in your Expo app. By using AuthView, UserButton, and UserProfileView, you replaced hundreds of lines of custom authentication code with a few simple components that deliver a secure, platform-native user experience. You also learned how to protect routes, handle session synchronization, and troubleshoot common issues. Your app is now ready to support email, password, social providers, and passkeys natively.

## Frequently asked questions

## FAQ

### How does AuthView differ from Clerk web components?

AuthView renders natively with SwiftUI on iOS and Jetpack Compose on Android, so it looks and behaves like a platform-native screen. The web components (`SignIn`, `SignUp`, `UserProfile`) are Clerk's React DOM components, available through the `@clerk/expo/web` entry point for the Expo web platform — they throw an error in native environments. Use AuthView for native mobile UI; use web components only when your app targets Expo web.

### Can I customize the appearance of AuthView?

AuthView uses native platform styling and adapts to iOS and Android design conventions automatically, including light and dark mode. Which authentication methods appear is configured in the Clerk Dashboard, not in code. For visual customization — colors, dark-mode palette, and border radius on both platforms, plus an iOS-only custom font family — point the `@clerk/expo` config plugin at a JSON theme file (see the [theming reference](https://clerk.com/docs/reference/expo/native-components/theming.md)). Deeper theming (`ClerkTheme`) is available at the Swift and Kotlin layer; theming is not exposed through React Native JavaScript props.

### How do I handle sign-out with native components?

`UserButton` and `UserProfileView` include built-in sign-out that syncs with the JavaScript SDK automatically. For a custom button, call `signOut()` from the `useAuth()` hook, then let your route-guard layout redirect once `isSignedIn` becomes `false` instead of navigating imperatively.

### Does AuthView handle errors like wrong passwords or invalid emails automatically?

Yes. AuthView displays all runtime errors internally. Wrong passwords, invalid emails, and identifier-not-found errors appear as inline messages below the relevant field; network and server errors appear in a native modal sheet; and verification-code requests are rate-limited with a visible 30-second cooldown. No error-handling code is required.

### What happens if the user loses network connectivity during authentication?

AuthView shows network errors in a native modal. For offline-first apps, Clerk offers experimental offline support via the `__experimental_resourceCache` property from `@clerk/expo/resource-cache` — see the [offline support guide](https://clerk.com/docs/guides/development/offline-support.md).

### Can I use AuthView alongside custom authentication flows?

Yes. AuthView can handle primary authentication while custom flows (`useSignIn`, `useSignUp`) cover specialized cases. Session state is shared across both.

### How do I test AuthView in my app?

Clerk testing tokens target web frameworks (Playwright, Cypress) and do not work with native rendering. For E2E, use [Maestro](https://maestro.mobile.dev/) with a dedicated Clerk development instance and pre-created test accounts. For integration tests, mock the Clerk hooks (`useAuth`, `useUser`, `useSession`).

## In this series

1. [How to Use AuthView in an Expo App: Native Authentication with Clerk](https://clerk.com/articles/how-to-use-authview-in-an-expo-app-native-authentication-with-clerk.md)
2. **How to Use AuthView in an Expo App: Native Authentication with Clerk - Part 2** (you are here)
