Generated banner for Clerk Expo
Generated logo for Clerk Expo

Clerk Expo

ClerkOfficialCreated by clerk

  • Skill
  • Tool integration
  • Software development
  • MIT
  • Low risk

From the author

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.
— the description by clerk

AutoGineer summary

Written by AutoGineer from the skill’s own files, not by the author

Clerk-expo provides a comprehensive suite of tools for managing user authentication in Expo and React Native projects. It supports both prebuilt native components for rapid implementation and custom flow hooks for tailored UI experiences. The skill covers essential authentication features including email/password, OTP, MFA, OAuth/SSO, and biometric login, while ensuring proper session management through secure token caching and Expo Router integration.

What it does

  • Provides prebuilt native components like AuthView and UserButton for rapid UI integration.
  • Supports custom authentication flows using hooks for full UI control.
  • Handles complex auth scenarios including MFA, social login, and biometric authentication.
  • Integrates with Expo Router for protected route management.
  • Manages secure session persistence via token caching.
  • Enables bot protection via native captcha mount points.

When to use it

  • When adding user authentication to an Expo or React Native application.
  • When you need to implement social login (Google, Apple) or passwordless flows.
  • When you require a secure, managed authentication system that supports MFA and biometrics.
  • When you need to protect specific routes or screens based on user authentication status.

Advantages

  • Rapid development with prebuilt native components.
  • Flexible architecture supporting both standard and custom UI requirements.
  • Automatic session synchronization between native and JavaScript layers.
  • Comprehensive support for modern auth standards like MFA and SSO.

Usage examples

“How do I add Clerk authentication to my new Expo project?”
The agent will guide you through the setup process, including installing the package, configuring the ClerkProvider with your publishable key, and implementing the AuthView component.
“I need to implement a custom sign-in screen with email and password.”
The agent will provide a code example using the useSignIn hook, demonstrating how to handle the sign-in state, errors, and the finalize method.
“How can I protect my dashboard route in Expo Router?”
The agent will show you how to use the useAuth hook to check the user's signed-in status and redirect them to a sign-in screen if they are unauthenticated.

Install

  1. Download the skill as a ZIP:

    https://mp-staging.autogineer.com/agent-skills/clerk/clerk-expo/download
  2. Unzip it into the cross-client skills folder of your project:

    mkdir -p .agents/skills && unzip clerk-expo.zip -d .agents/skills

Documentation by clerk

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"Custom flow additionsreferences/custom-flows.md
"Email link"Expo web custom flow; native apps use email codes for custom UI or <AuthView /> in a development buildreferences/custom-flows.md + references/prebuilt-components.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. For initial application setup, existing-app linking, or missing keys, follow the canonical clerk-setup skill. Don't start a separate init flow here. Then follow the Expo setup reference for provider, token cache, config plugin, and build-type steps not already completed.

  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 in app code. Never NEXT_PUBLIC_, never hardcoded. If the key is missing, follow the appropriate new or existing application path in clerk-setup. Expo has no accountless keys, and an agent's init won't write one without a target application, even when signed in. For a new application, have the developer sign in and select or create an application, then run npx -y clerk@latest init --app <application_id>. For an existing application, have them sign in, link the selected application if needed, then run npx -y clerk@latest env pull. Alternatively, ask the developer for the publishable key from Clerk Dashboard → API keys and wait. Don't continue until a real key is set, and never run a fresh init for an existing Clerk project.

  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

  • clerk — top-level router

  • clerk-swift / clerk-android — native mobile SDKs

  • clerk-orgs, clerk-billing, clerk-webhooks — feature skills (hooks work the same in Expo)

  • Installed package source: node_modules/@clerk/expo/

  • Expo quickstart

  • Expo SDK reference

  • Clerk Expo quickstart examples — three official example apps: JS-only (Expo Go), JS + native sign-in buttons, native components

Files

references/recipes.md

Recipes: users, orgs, sign-out, backend calls, device features

Post-auth patterns. Hooks below are imported from @clerk/expo unless noted; they mirror @clerk/react.

Canonical docs (fetch to re-verify if the installed SDK is newer than 3.6.x): Expo SDK reference — plus local-credentials and passkeys pages under the Expo reference

User profile data

import { useUser } from '@clerk/expo'

const { user, isLoaded } = useUser()
// user is null until loaded/signed in — always guard
// user.fullName, user.firstName, user.imageUrl, user.primaryEmailAddress?.emailAddress

For a full profile management UI on a dev build, prefer the native UserProfileView / UserButton (prebuilt-components.md) over hand-built screens.

Sign out

import { useClerk } from '@clerk/expo'

const { signOut } = useClerk()
<Pressable onPress={() => signOut()}>...</Pressable>

Organization switching (B2B)

Organizations must be enabled in the dashboard. For deeper org work (roles, invitations, RBAC) load the clerk-orgs skill — the hooks are identical in Expo.

import { useOrganization, useOrganizationList } from '@clerk/expo'

const { organization } = useOrganization()
const { setActive, userMemberships } = useOrganizationList({
  userMemberships: { infinite: true },
})

// Current: organization?.name ?? 'Personal account'
// Switch: setActive({ organization: membership.organization.id })
// List: userMemberships.data?.map((m) => m.organization) — guard while undefined

Calling your backend

Route guards are client-side only; authorize on the server:

import { useAuth } from '@clerk/expo'

const { getToken } = useAuth()
const res = await fetch(`${API_URL}/endpoint`, {
  headers: { Authorization: `Bearer ${await getToken()}` },
})

Verify the token server-side with Clerk's backend SDK for your server framework (e.g. @clerk/backend's verifyToken, or the framework SDK's getAuth). Clerk has no official Expo Router API-routes (+api.ts) integration — treat any server code as a normal backend and use @clerk/backend.

Push notifications with user context

Associate the Expo push token with the Clerk user:

import { useUser } from '@clerk/expo'
import * as Notifications from 'expo-notifications'
import { useEffect } from 'react'

export function PushTokenRegistrar() {
  const { user, isLoaded } = useUser()

  useEffect(() => {
    if (!isLoaded || !user) return
    ;(async () => {
      const { status } = await Notifications.requestPermissionsAsync()
      if (status !== 'granted') return
      const token = (await Notifications.getExpoPushTokenAsync()).data
      await user.update({
        unsafeMetadata: { ...user.unsafeMetadata, expoPushToken: token },
      })
    })()
  }, [isLoaded, user])

  return null
}
  • unsafeMetadata is client-writable; anything that must be trusted belongs in publicMetadata, written server-side via the Backend SDK.

  • Server send: look up the user with the Backend SDK, read unsafeMetadata.expoPushToken, POST to https://exp.host/--/api/v2/push/send.

  • Re-register after sign-out/sign-in as a different user.

Biometric re-auth — useLocalCredentials()

Dev build only. Stores the user's credentials in the keychain, gated by Face ID / Touch ID / device biometrics, for fast re-sign-in.

Prerequisites: npx expo install expo-local-authentication (plus expo-secure-store from setup), iOS NSFaceIDUsageDescription in app.json → ios.infoPlist.

import { useLocalCredentials } from '@clerk/expo/local-credentials'

const { hasCredentials, setCredentials, authenticate, biometricType } = useLocalCredentials()

// After a successful password sign-in, offer to enable biometrics:
await setCredentials({ identifier: emailAddress, password })

// On later launches, if hasCredentials:
const signInResource = await authenticate() // prompts biometrics, performs the sign-in

Password-based instances only — it replays stored credentials. Confirm the exact return shape against node_modules/@clerk/expo/dist/local-credentials/*.d.ts before wiring UI.

Passkeys

Dev build only. Install the separate @clerk/expo-passkeys package, then import from the @clerk/expo/passkeys subpath — the subpath re-exports the peer package (this install/import pairing is intentional and matches the docs). Pass it to the provider and enable passkeys in the dashboard:

import { passkeys } from '@clerk/expo/passkeys'

<ClerkProvider publishableKey={publishableKey} tokenCache={tokenCache} __experimental_passkeys={passkeys}>

Requires associated-domains setup (iOS) / asset links (Android). Fetch the Expo passkeys reference for the current platform configuration before implementing — the passkeys API is still experimental and changes.

Offline resource caching

If Clerk resources (user, session) should survive offline cold starts, pass resourceCache from @clerk/expo/resource-cache to the provider (__experimental_resourceCache). @clerk/expo/secure-store is the deprecated alias — never use it in new code.

Requirements and compatibility

Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta

“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.

Needs: Declares allowed tools, Needs an API key, Needs Node.js

The author says: Requires @clerk/expo v3.4+ (written against v3.6.x, July 2026). Expo SDK 53-56, React Native 0.75+.

Security

What our scanner noticed· Low risk

  • Instructions that use the network

A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.

Attribution and licence

Created by
clerk
Publisher
Clerk (Official)
Source
clerk/skills · skills/clerk-expo · commit c5d2c0d
Licence
MIT License (redistribution allowed)
  • ATTRIBUTION.md (written by AutoGineer)
Synced

AutoGineer is not affiliated with or endorsed by clerk.

Download ZIP

The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download clerk-expo.zip