PluginBench
Skill
Official
Pass
Audit score 90

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
Prerequisites
  • @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
Claude Code
Cursor
Windsurf
Cline

How to use clerk-expo

  1. 1.Install @clerk/expo and configure the publishable key in .env as EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY
  2. 2.Wrap your app with ClerkProvider and configure the token cache from @clerk/expo/token-cache
  3. 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. 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. 5.For protected routes, use Expo Router guards with useAuth() to check isSignedIn and redirect unsigned users
  6. 6.Test by signing in manually, then restart the app to verify the session persists via token cache

Use cases

Good for
  • 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
Who it's for
  • 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

Should I use prebuilt components or custom flows?

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.

What is the difference between useSignIn() and the legacy pattern?

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.

Do native components work in Expo Go?

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.

How do I enable SMS or phone OTP authentication?

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().

What should I do if my build fails?

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, expo in package.json, metro.config.js, @clerk/expo dependency).

Route away when:

  • Native iOS/Swift project (.xcodeproj, Package.swift) → clerk-swift
  • Native Android/Kotlin project (build.gradle without 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)PathReference
"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 requiredCustom flowsreferences/setup.md + references/custom-flows.md
"Add phone / SMS auth", "email OTP", "passwordless"Custom flow, phoneCode / emailCodereferences/custom-flows.md
"Sign in with Google/Apple/GitHub", "social login", "SSO"Browser SSO or native buttonsreferences/sso-and-native-auth.md
"MFA / 2FA / TOTP", "forgot password", "email link"Custom flow additionsreferences/custom-flows.md
"Protect routes/screens", "redirect if signed out"Expo Router guardsreferences/protected-routes.md
"Show user profile", "org switching", "push notifications", "sign out", "call my backend"App recipesreferences/recipes.md
"Biometric login", "Face ID", "passkeys"Device featuresreferences/recipes.md

Default Path Decision

When the user says "add auth" without specifying UI:

  1. Default to prebuilt native components (AuthView + UserButton from @clerk/expo/native). Fastest to working auth; UI is maintained by Clerk. Tell the developer they are in beta and require a development build.
  2. 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.
  3. 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

  1. Confirm project type (Expo/RN) and pick the path per the Intent Map / Default Path rules.
  2. Follow references/setup.md: install, env key, provider, token cache, config plugin, build type.
  3. Verify dashboard prerequisites (Gate 2 and Gate 3 below).
  4. Implement from the selected reference only.
  5. Verify by building, not just by writing:
    • Run the project's typecheck (npx tsc --noEmit or equivalent).
    • Build and launch: npx expo run:ios / run:android for native features, npx expo start for 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).

Execution Gates (Do Not Skip)

  1. Publishable key — Read from process.env.EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY (.env file). Never NEXT_PUBLIC_, never hardcoded. If no key exists, ask the developer for one (or run npx clerk@latest init --framework expo, which installs the SDK and writes the env file) and wait before editing files.
  2. 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.
  3. 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.
  4. 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: destructuring isLoaded/setActive from useSignIn()/useSignUp() (the current hooks don't return them), or signIn.create() chained with prepareFirstFactor()/attemptFirstFactor() + setActive({ session }). That pattern lives at @clerk/expo/legacy and is only for maintaining existing legacy code, never for new work. Scope notes: isLoaded from useAuth()/useUser() is current API and required in guards; signIn.create() itself still exists for advanced cases — prefer the factor-specific methods.
  5. useSSO(), never useOAuth() — useOAuth is deprecated. Note the asymmetry: startSSOFlow() still returns { createdSessionId, setActive } and requires setActive({ session: createdSessionId }) — SSO does not use finalize().
  6. Token cache — tokenCache from @clerk/expo/token-cache on ClerkProvider. Never use expo-secure-store directly for session tokens, never AsyncStorage.
  7. resourceCache, never secureStore — if offline resource caching comes up, @clerk/expo/secure-store is deprecated; use resourceCache from @clerk/expo/resource-cache.
  8. 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/web components or custom flows. State the build requirement before implementing a native-only feature.
  9. Combined sign-in-or-up default — one combined flow unless the developer asks for separate sign-in and sign-up screens.
  10. 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.
  11. 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.ts and package.json exports. The installed version wins over this skill if they disagree.
  12. Freshness gate — this skill was verified against @clerk/expo 3.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.ts before 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 theme JSON file for native component styling (see references/prebuilt-components.md).
  • Native Google sign-in will move to a separate @clerk/expo-google-signin package in the next major (the @clerk/expo/google import keeps working in v3; a dev warning announces the migration). Don't preinstall the new package on v3.

Common Pitfalls

LevelIssuePrevention
CRITICALGenerating legacy custom-flow code (signIn.create + prepareFirstFactor + setActive)Use the current method-based API (Gate 4)
CRITICALUsing useOAuth()Use useSSO() (Gate 5)
CRITICALImplementing SMS/social auth without checking the factor is enabledCheck environment/dashboard first (Gate 3)
CRITICALNative components targeted at Expo Go or webRequire a dev build; offer custom flows otherwise (Gate 8)
CRITICALSign-up screen missing <View nativeID="clerk-captcha" />Always include it (Gate 10)
HIGHNEXT_PUBLIC_ env prefix, or env var read inside node_modulesEXPO_PUBLIC_CLERK_PUBLISHABLE_KEY, passed explicitly to ClerkProvider
HIGHSession lost on restarttokenCache from @clerk/expo/token-cache on the provider
HIGHCalling setActive() after AuthView / UserButton authNative components sync sessions automatically
HIGHPairing AuthView with useSignInWithGoogle/useSignInWithAppleAuthView renders enabled social providers itself
HIGHCalling WebBrowser.maybeCompleteAuthSession() manuallyClerkProvider handles it
HIGHSplitting sign-in / sign-up without being askedCombined flow by default (Gate 9)
MEDIUMMissing isLoaded check before isSignedIn in guardsAlways gate on isLoaded first
MEDIUMUsing yalc/pnpm link for local @clerk/expo developmentUse Verdaccio or pkg.pr.new

See Also