clerk-expo
clerk/skills
Add Clerk authentication to Expo and React Native apps with prebuilt components or custom flows.
What is clerk-expo?
Clerk Expo integrates authentication into Expo and React Native projects using @clerk/expo. Use it for sign-in/sign-up flows, OAuth/SSO, native biometrics, MFA, and protected routes in mobile apps. Do not use for native iOS/Swift, native Android/Kotlin, or web-only frameworks.
- Prebuilt native authentication components (AuthView, UserButton) with optional theming
- Custom sign-in/sign-up flows supporting email, password, SMS/phone OTP, and MFA
- Native Google and Apple sign-in buttons and biometric authentication
- OAuth and SSO integration via browser-based flows
- Protected routes and screens in Expo Router with automatic redirects
- Session management with secure token caching and offline resource support
How to install clerk-expo
npx skills add https://github.com/clerk/skills --skill clerk-expo- @clerk/expo v3.4+ (tested against v3.6.x)
- Expo SDK 53–56 and React Native 0.75+
- Clerk publishable key from environment variable EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY
- Native API enabled in Clerk Dashboard (Native applications section)
- Development build for native components and hooks (npx expo run:ios/android); Expo Go for custom flows only
How to use clerk-expo
- 1.Install @clerk/expo and configure the publishable key in .env as EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY
- 2.Wrap your app with ClerkProvider and configure the token cache from @clerk/expo/token-cache
- 3.Add the Clerk config plugin to app.json or app.config.js and run a development build (npx expo run:ios or run:android)
- 4.Choose your path: use prebuilt AuthView and UserButton components for fastest setup, or implement custom flows with useSignIn() and useSignUp() hooks for custom UI
- 5.For protected routes, use Expo Router guards with useAuth() to check isSignedIn and redirect unsigned users
- 6.Test by signing in manually, then restart the app to verify the session persists via token cache
Use cases
- Building a mobile app with email/password or phone-based authentication
- Adding social login (Google, Apple, GitHub) to an Expo app
- Implementing passwordless sign-in via email links or SMS codes
- Protecting app screens so only authenticated users can access them
- Adding multi-factor authentication (TOTP, SMS) to existing sign-in flows
- Mobile app developers using Expo or React Native
- Teams building cross-platform apps with native authentication features
- Developers migrating from web frameworks to mobile and needing auth
- Projects requiring biometric or native platform sign-in options
clerk-expo FAQ
Default to prebuilt AuthView and UserButton components for fastest time-to-market; they require a development build but handle UI maintenance. Switch to custom flows if you need Expo Go support, web targets, or custom branding.
Current API uses useSignIn() returning { signIn, errors, fetchStatus } with factor-specific methods like signIn.password() and signIn.finalize(). The legacy pattern (signIn.create() + prepareFirstFactor()) is only for maintaining existing code, never for new work.
No. Native components (AuthView, UserButton) and native hooks (useSignInWithGoogle, useSignInWithApple) require a development build (npx expo run:ios/android). For Expo Go, use custom flows instead.
Confirm SMS is enabled in your Clerk instance (Clerk Dashboard → User & authentication → SMS). Then use custom flows with signIn.phoneCode.sendCode() and signIn.phoneCode.attemptPhoneCodeVerification().
Build errors against the installed SDK are the ground truth. Check node_modules/@clerk/expo/dist/native/*.d.ts for current component props and hook signatures, then iterate fixes. After ~5 failed attempts, ask the developer how to proceed.
Full instructions (SKILL.md)
Source of truth, from clerk/skills.
name: clerk-expo description: Add Clerk authentication to Expo and React Native apps using @clerk/expo. Use for Expo setup, prebuilt native components (AuthView, UserButton), custom sign-in/sign-up flows (email, password, SMS/phone OTP, MFA), OAuth/SSO, native Google/Apple sign-in, Expo Router protected routes, biometrics, and push notifications. Do not use for native Swift/iOS, native Android/Kotlin, or web-only framework projects. license: MIT allowed-tools: WebFetch metadata: author: clerk version: 2.0.0 compatibility: Requires @clerk/expo v3.4+ (written against v3.6.x, July 2026). Expo SDK 53-56, React Native 0.75+.
Clerk Expo (React Native)
Implement Clerk in Expo / React Native projects. This skill inlines verified patterns for the stable surface (provider, token cache, flows) and requires source inspection of the installed @clerk/expo package for anything volatile (component props, hook signatures).
Activation Rules
Activate when either is true:
- The user asks for auth in an Expo or React Native app, or mentions
@clerk/expo,ClerkProvider, Expo Router auth, or Clerk hooks in a native app. - The project is Expo/React Native (
app.json/app.config.js,expoinpackage.json,metro.config.js,@clerk/expodependency).
Route away when:
- Native iOS/Swift project (
.xcodeproj,Package.swift) →clerk-swift - Native Android/Kotlin project (
build.gradlewithout React Native) →clerk-android - Web-only framework (Next.js, Remix, plain React, etc.) → the matching framework skill
Intent Map
Match what the user asked for, then load the reference(s) listed. Load only what the task needs.
| User intent (examples) | Path | Reference |
|---|---|---|
| "Add auth to my app" / "add sign-in with Clerk" | Prebuilt native components (default) | references/setup.md + references/prebuilt-components.md |
| "Add auth" but Expo Go / web / custom UI required | Custom flows | references/setup.md + references/custom-flows.md |
| "Add phone / SMS auth", "email OTP", "passwordless" | Custom flow, phoneCode / emailCode | references/custom-flows.md |
| "Sign in with Google/Apple/GitHub", "social login", "SSO" | Browser SSO or native buttons | references/sso-and-native-auth.md |
| "MFA / 2FA / TOTP", "forgot password", "email link" | Custom flow additions | references/custom-flows.md |
| "Protect routes/screens", "redirect if signed out" | Expo Router guards | references/protected-routes.md |
| "Show user profile", "org switching", "push notifications", "sign out", "call my backend" | App recipes | references/recipes.md |
| "Biometric login", "Face ID", "passkeys" | Device features | references/recipes.md |
Default Path Decision
When the user says "add auth" without specifying UI:
- Default to prebuilt native components (
AuthView+UserButtonfrom@clerk/expo/native). Fastest to working auth; UI is maintained by Clerk. Tell the developer they are in beta and require a development build. - Fall back to custom flows when any of these hold — say why when you switch:
- The project must run in Expo Go (no dev build).
- The app targets web (native components don't render on web).
- The developer wants their own UI or a specific brand experience beyond theming.
- If the developer has an existing auth UI, extend what's there — don't rip out custom flows to insert
AuthView(or vice versa) without being asked.
Do not blend prebuilt components and custom flows for the same auth step (e.g. AuthView plus a custom password form). Blending is allowed only when the developer explicitly asks.
Quick Workflow
- Confirm project type (Expo/RN) and pick the path per the Intent Map / Default Path rules.
- Follow references/setup.md: install, env key, provider, token cache, config plugin, build type.
- Verify dashboard prerequisites (Gate 2 and Gate 3 below).
- Implement from the selected reference only.
- Verify by building, not just by writing:
- Run the project's typecheck (
npx tsc --noEmitor equivalent). - Build and launch:
npx expo run:ios/run:androidfor native features,npx expo startfor Expo Go flows. If the build fails, fix and rebuild iteratively — build errors against the installed SDK are the ground truth when this skill and the SDK disagree. After ~5 failed fix attempts, stop and ask the developer how to proceed instead of thrashing. - Walk the developer through one real sign-in, then confirm the session survives an app restart (token cache working).
- Run the project's typecheck (
Execution Gates (Do Not Skip)
- Publishable key — Read from
process.env.EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY(.envfile). NeverNEXT_PUBLIC_, never hardcoded. If no key exists, ask the developer for one (or runnpx clerk@latest init --framework expo, which installs the SDK and writes the env file) and wait before editing files. - Native API dashboard toggle — Clerk's Native API must be enabled for the instance: Clerk Dashboard → Native applications (
https://dashboard.clerk.com/~/native-applications). Tell the developer to verify this during setup; it is required for any native integration. - Factor availability — Before implementing a specific strategy (SMS, email code, social provider), confirm it's enabled for the instance. Derive the Frontend API URL from the publishable key (base64-decode the middle segment) and fetch
<frontendApiUrl>/v1/environment?_is_native=true, or ask the developer to check the dashboard (User & authentication). SMS in particular is instance-configuration-dependent — code written for a disabled factor fails at runtime, not build time. - Current custom-flows API only —
useSignIn()/useSignUp()from@clerk/expo(v3.4+) return{ signIn, errors, fetchStatus }and use method-based flows:signIn.password(),signIn.phoneCode.sendCode(),signIn.finalize(). Never generate the legacy pattern: destructuringisLoaded/setActivefromuseSignIn()/useSignUp()(the current hooks don't return them), orsignIn.create()chained withprepareFirstFactor()/attemptFirstFactor()+setActive({ session }). That pattern lives at@clerk/expo/legacyand is only for maintaining existing legacy code, never for new work. Scope notes:isLoadedfromuseAuth()/useUser()is current API and required in guards;signIn.create()itself still exists for advanced cases — prefer the factor-specific methods. useSSO(), neveruseOAuth()—useOAuthis deprecated. Note the asymmetry:startSSOFlow()still returns{ createdSessionId, setActive }and requiressetActive({ session: createdSessionId })— SSO does not usefinalize().- Token cache —
tokenCachefrom@clerk/expo/token-cacheonClerkProvider. Never useexpo-secure-storedirectly for session tokens, never AsyncStorage. resourceCache, neversecureStore— if offline resource caching comes up,@clerk/expo/secure-storeis deprecated; useresourceCachefrom@clerk/expo/resource-cache.- Build-type gating — Native components (
@clerk/expo/native) and native hooks (useSignInWithGoogle,useSignInWithApple,useLocalCredentials) require a development build (npx expo run:ios/run:android), not Expo Go, and don't exist on web. For web targets use@clerk/expo/webcomponents or custom flows. State the build requirement before implementing a native-only feature. - Combined sign-in-or-up default — one combined flow unless the developer asks for separate sign-in and sign-up screens.
- Bot protection — custom sign-up screens must render
<View nativeID="clerk-captcha" />; Clerk's bot protection is on by default and needs this mount point. - Source verification for volatile surfaces — before using native component props or native hook options, confirm against the installed package:
node_modules/@clerk/expo/dist/native/*.d.tsandpackage.jsonexports. The installed version wins over this skill if they disagree. - Freshness gate — this skill was verified against
@clerk/expo3.6.x. Check the installed version (node_modules/@clerk/expo/package.json). If it is a newer minor or major, treat this skill's code snippets as suspect: re-verify against the docs URL cited next to each snippet (every reference section carries one) or the installed.d.tsbefore using them. If it is older than 3.4, the method-based custom-flows API may not exist — offer an upgrade instead of writing legacy code.
Version Notes (v3.5–v3.6, June 2026)
- Minimum React Native raised to 0.75 in v3.5.0 (iOS SDK now links via SPM podspec). Peer range:
expo >=53 <57. - Native components matured: iOS moved to Expo Modules; native↔JS session sync is automatic and bidirectional — never call
setActive()after native-component auth. - The config plugin accepts a
themeJSON file for native component styling (see references/prebuilt-components.md). - Native Google sign-in will move to a separate
@clerk/expo-google-signinpackage in the next major (the@clerk/expo/googleimport keeps working in v3; a dev warning announces the migration). Don't preinstall the new package on v3.
Common Pitfalls
| Level | Issue | Prevention |
|---|---|---|
| CRITICAL | Generating legacy custom-flow code (signIn.create + prepareFirstFactor + setActive) | Use the current method-based API (Gate 4) |
| CRITICAL | Using useOAuth() | Use useSSO() (Gate 5) |
| CRITICAL | Implementing SMS/social auth without checking the factor is enabled | Check environment/dashboard first (Gate 3) |
| CRITICAL | Native components targeted at Expo Go or web | Require a dev build; offer custom flows otherwise (Gate 8) |
| CRITICAL | Sign-up screen missing <View nativeID="clerk-captcha" /> | Always include it (Gate 10) |
| HIGH | NEXT_PUBLIC_ env prefix, or env var read inside node_modules | EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY, passed explicitly to ClerkProvider |
| HIGH | Session lost on restart | tokenCache from @clerk/expo/token-cache on the provider |
| HIGH | Calling setActive() after AuthView / UserButton auth | Native components sync sessions automatically |
| HIGH | Pairing AuthView with useSignInWithGoogle/useSignInWithApple | AuthView renders enabled social providers itself |
| HIGH | Calling WebBrowser.maybeCompleteAuthSession() manually | ClerkProvider handles it |
| HIGH | Splitting sign-in / sign-up without being asked | Combined flow by default (Gate 9) |
| MEDIUM | Missing isLoaded check before isSignedIn in guards | Always gate on isLoaded first |
| MEDIUM | Using yalc/pnpm link for local @clerk/expo development | Use Verdaccio or pkg.pr.new |
See Also
clerk— top-level routerclerk-swift/clerk-android— native mobile SDKsclerk-orgs,clerk-billing,clerk-webhooks— feature skills (hooks work the same in Expo)- Installed package source:
node_modules/@clerk/expo/ - https://clerk.com/docs/getting-started/quickstart (Expo SDK tab)
- https://clerk.com/docs/reference/expo/overview
- https://github.com/clerk/clerk-expo-quickstart — three official example apps: JS-only (Expo Go), JS + native sign-in buttons, native components
Related skills
More from clerk/skills and the wider catalog.

clerk-expo-patterns
Secure token storage, OAuth, and protected routes for Expo/React Native apps with Clerk.

clerk-nextjs-patterns
Advanced Next.js patterns for authentication with Clerk: middleware, Server Actions, caching, and JWT verification.

clerk-nuxt-patterns
Nuxt 3 authentication patterns with @clerk/nuxt—middleware, composables, server routes, and SSR.

clerk-orgs
Multi-tenant B2B organizations with roles, permissions, SSO, and member management for Next.js apps.

clerk-react-patterns
React SPA auth patterns with @clerk/react for Vite/CRA—hooks, protected routes, custom flows.

clerk-react-router-patterns
React Router v7/v8 patterns with Clerk — auth in loaders, protected routes, SSR, and org switching.