All skills
clerk avatar

/clerk-expo

@3d0c898 official
by clerkclerk/skills83 stars
5

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.

Use this Skill: https://skilld.dev/gh/clerk/skills/clerk-expo

This session only. Nothing lands on disk.

referencessso-and-native-auth.md

≈1.5k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Social auth: browser SSO and native Google/Apple

Canonical docs (fetch to re-verify if the installed SDK is newer than 3.6.x):

Three ways to do social auth in Expo. Pick by platform and build type:

Approach UX Works in Expo Go Platforms
AuthView (prebuilt) Native, renders all enabled providers No (dev build) iOS, Android
useSSO() browser flow Opens a browser session Yes iOS, Android, web
useSignInWithGoogle() / useSignInWithApple() Fully native sheet, no browser No (dev build) Google: iOS+Android; Apple: iOS only

If the app already uses AuthView, stop — it handles social providers itself; configure providers in the dashboard instead. Whatever the approach, the provider must be enabled in Clerk Dashboard → User & authentication → Social connections (Gate 3).

Browser SSO — useSSO()

Never useOAuth() (deprecated). Prerequisites: npx expo install expo-auth-session expo-web-browser, and a deep-link "scheme" in app.json.

import { useSSO } from '@clerk/expo'

const { startSSOFlow } = useSSO()

const onPress = async () => {
  try {
    const { createdSessionId, setActive, signUp } = await startSSOFlow({
      strategy: 'oauth_google', // oauth_apple, oauth_github, oauth_microsoft, ...
    })
    if (createdSessionId) {
      await setActive!({ session: createdSessionId })
      router.replace('/')
    } else if (signUp?.status === 'missing_requirements') {
      // Instance requires fields the provider didn't supply (e.g. username) —
      // collect them and signUp.update(...), or relax requirements in the dashboard
    }
    // No createdSessionId and no missing requirements → user cancelled; do nothing.
  } catch (err) {
    console.error(JSON.stringify(err, null, 2))
  }
}

Behavior that is handled for you — do not reimplement:

  • redirectUrl defaults to AuthSession.makeRedirectUri({ path: 'sso-callback' }); only override for a custom callback route.
  • ClerkProvider calls WebBrowser.maybeCompleteAuthSession() — never add it manually.
  • The transfer flow (account exists → sign-in, new account → sign-up with transfer: true) runs inside startSSOFlow.
  • User cancellation is not an error: it resolves with createdSessionId: null. Don't show error UI for it.

Enterprise SSO/SAML: startSSOFlow({ strategy: 'enterprise_sso', identifier: email }).

Note: SSO is the one flow that still uses setActive({ session: createdSessionId }) — the finalize() method from custom-flows.md does not apply here.

Native Google sign-in — useSignInWithGoogle()

Fully native Google sheet (Credential Manager on Android). Dev build only.

Setup:

  1. npx expo install expo-crypto
  2. Env vars in .env (values from the Google Cloud OAuth clients configured for the Clerk instance):
    • EXPO_PUBLIC_CLERK_GOOGLE_WEB_CLIENT_ID (always required)
    • EXPO_PUBLIC_CLERK_GOOGLE_IOS_CLIENT_ID (iOS)
    • EXPO_PUBLIC_CLERK_GOOGLE_IOS_URL_SCHEME (iOS — the config plugin writes it into the iOS URL types at prebuild; prebuild fails without it)
  3. @clerk/expo config plugin registered, then rebuild.

Full provider-side setup lives at https://clerk.com/docs/guides/configure/auth-strategies/sign-in-with-google — fetch it if the Google Cloud side isn't already configured.

import { useSignInWithGoogle } from '@clerk/expo/google'
import { Platform } from 'react-native'

const { startGoogleAuthenticationFlow } = useSignInWithGoogle()

const onPress = async () => {
  try {
    const { createdSessionId, setActive } = await startGoogleAuthenticationFlow()
    if (createdSessionId && setActive) {
      await setActive({ session: createdSessionId })
      router.replace('/')
    }
  } catch (err: any) {
    if (err.code === 'SIGN_IN_CANCELLED' || err.code === '-5') return // user cancelled
    console.error('Sign in with Google error:', JSON.stringify(err, null, 2))
  }
}

// Render the button only where supported:
if (Platform.OS !== 'ios' && Platform.OS !== 'android') return null

Always wrap in try/catch and swallow the cancellation codes. On unsupported platforms (web), fall back to useSSO({ strategy: 'oauth_google' }) or hide the button.

Next-major note: native Google sign-in moves to a separate @clerk/expo-google-signin package (plus its own config plugin) in the next major version. On v3 the @clerk/expo/google import is correct and logs a dev-only migration warning — don't preinstall the new package.

Native Apple sign-in — useSignInWithApple()

iOS only; dev build only. Requires npx expo install expo-apple-authentication and the Sign in with Apple capability (the expo-apple-authentication plugin handles the entitlement — add it to app.json plugins). Full setup: https://clerk.com/docs/guides/configure/auth-strategies/sign-in-with-apple

import { useSignInWithApple } from '@clerk/expo/apple'

const { startAppleAuthenticationFlow } = useSignInWithApple()
// identical result handling to the Google hook: setActive on createdSessionId, swallow cancellation

On Android/web, fall back to useSSO({ strategy: 'oauth_apple' }) or hide the button. App Store policy: apps offering third-party sign-in on iOS generally must also offer Sign in with Apple — mention this when adding Google-only auth to an iOS app.

Verification checklist

  • Provider enabled in the dashboard before writing code.
  • useSSO path: scheme configured, no manual maybeCompleteAuthSession, cancellation silent, setActive called on createdSessionId.
  • Native hooks: dev build stated, platform-gated rendering, cancellation codes swallowed, browser-SSO or hidden-button fallback for unsupported platforms.
  • Not paired with AuthView.
  • One real provider round-trip tested on a device or simulator.

Source: SKILL.md on GitHub

No alerts16d3 checks · Risk SAFE
  • Gen Agent Trust Hub16d

    The analyzed skill defines safe, verified integration patterns for the @clerk/expo authentication library in Expo and React Native applications. It appropriately specifies standard secret management guidelines (storing publishable keys in environment files rather than hardcoding them) and does not exhibit any malicious behaviors such as data exfiltration, prompt injection, or obfuscation.

  • Socket16d

    No alerts

  • Snyk16d

    Risk: LOW · No issues

Signed by skilld at 3d0c898. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub yesterday.

Activeupdated 3 months ago
What it can do
Network
metadata
{
  "author": "clerk",
  "version": "2.0.0"
}
All 1 allowed tools
WebFetch
Other metadata
compatibility
Requires @clerk/expo v3.4+ (written against v3.6.x, July 2026). Expo SDK 53-56, React Native 0.75+.

README badge

README badge for clerk/skills/clerk-expo

Implements Clerk authentication in Expo and React Native projects using @clerk/expo, supporting either prebuilt AuthView/UserButton components or custom hook-driven flows. Handles ClerkProvider setup, token persistence, native sign-in strategies, and Expo config plugin registration—excludes native iOS/Swift, native Android/Kotlin, and web-only frameworks.

Generated from the current SKILL.md.

Does this skill work with native iOS/Swift or native Android/Kotlin projects?
No. This skill is for Expo and React Native only. Native iOS/Swift and native Android/Kotlin projects should use their respective Clerk SDKs, not this skill.
Do I need a development build or can I use Expo Go?
Native components like AuthView and UserButton require an iOS/Android development build. Expo Go does not support native modules. For web targets, use the @clerk/expo/web exports instead.
What's the difference between prebuilt and custom flows?
Prebuilt uses Clerk's AuthView or UserButton components for the fastest setup. Custom hook-driven flows give you full control over the UI and authentication state but require more implementation work.
Do I need to set the publishable key via environment variables?
No. Pass the publishable key directly to <ClerkProvider publishableKey={key}> unless you explicitly ask for environment-variable indirection. The skill will not introduce env-var wiring by default.
Does this skill cover Expo-specific recipes like token caching and protected routes?
This skill covers flow selection and end-to-end setup. Expo-specific recipes (SecureStore token cache, OAuth deep-link configuration, Expo Router protected routes) are in the clerk-expo-patterns skill instead.

Generated from the current SKILL.md. These answers refresh after source changes.