This documentation is available as Markdown for AI agents and LLMs. See the full Markdown index or append .md to any documentation URL.
使用 Clerk
编辑页面
了解如何在你的 Expo 和 React Native 项目中添加 Clerk 身份验证和用户管理。
Clerk 是一个身份验证和用户管理平台,提供注册、登录、多因素身份验证、社交登录、组织以及托管用户数据库等功能。@clerk/expo SDK 为你提供 React hooks、控制组件、托管身份验证,以及预构建的原生 UI 组件。这些组件在 Android 上使用 Jetpack Compose 渲染,在 iOS 上使用 SwiftUI 渲染。
本指南将介绍如何安装 @clerk/expo、将应用包装在 <ClerkProvider> 中,以及如何选择适合项目的集成方式。本指南面向 @clerk/expo 4.x,该版本支持 Expo SDK 54 及更高版本。
选择你的集成方式
@clerk/expo 支持三种方式。请选择符合你需求的方式。之后你可以随时切换,而无需重写应用。
| 方式 | 你需要构建的内容 | 可在 Expo Go 中运行 | 最适合 |
|---|---|---|---|
| 托管身份验证 | 一个按钮,用于在浏览器身份验证会话中打开 Clerk 的账户门户 | 最快速的设置方式,并启用控制面板中的所有方法 | |
| 原生 UI 组件 | 从 @clerk/expo/native 中直接使用 <AuthView />、<UserButton /> 和 <UserProfileView /> | 完整的原生登录和账户管理 UI | |
| 自定义流程 | 自行构建 React Native 界面,并调用 useSignUp() 和 useSignIn() 等 hooks | 最大程度的 UI 控制 |
@clerk/expo/native中的原生 UI 组件目前处于 beta 阶段。它们在 Android 上使用 Jetpack Compose 渲染,在 iOS 上使用 SwiftUI 渲染,并且会将已登录会话同步回 JavaScript SDK,因此所有@clerk/expohooks(例如useAuth()和useUser())都会保持同步。
前置条件
4 requirements
4 requirements
1.
在 Clerk Dashboard 注册并创建一个应用。
2.
打开 Clerk Dashboard 中的 Native applications 页面,并确保 Native API 已开启。对于任何使用 @clerk/expo 的 Expo 集成都需要这样做。
3.
@clerk/expo Core 3 的 peer dependency 是 expo: >=53 <56。
4.
原生 UI 组件和原生登录 hooks 需要开发构建版本。托管身份验证和自定义流程也可以在 Expo Go 中运行。
安装并配置 Clerk
1
安装 @clerk/expo 和 expo-secure-store
使用 npx expo install,以确保版本与你的 Expo SDK 匹配:
- npx expo install @clerk/expo expo-secure-storeexpo-secure-store 是一个 peer dependency。Clerk 通过 @clerk/expo/token-cache 使用它,利用 iOS Keychain 和 Android Keystore 对会话令牌进行加密。
对于托管身份验证,还需要安装 Clerk 用于打开浏览器身份验证会话的包:
- npx expo install expo-auth-session expo-crypto expo-web-browser如果你计划在自定义流程中添加原生使用 Google 登录的按钮,请安装 @clerk/expo-google-signin 和 expo-crypto:
- npx expo install @clerk/expo-google-signin expo-crypto对于原生使用 Apple 登录的按钮,请同时安装 expo-apple-authentication 和 expo-crypto:
- npx expo install expo-apple-authentication expo-crypto如果你只使用 @clerk/expo/native 中的 <AuthView />,则不需要这些额外包,因为该组件会在内部处理社交登录流程。
2
验证配置插件
将 @clerk/expo 和 expo-secure-store 添加到 应用配置 中的 plugins 数组。如果你的项目使用静态 app.json,并且通过 npx expo install 安装了这些包,Expo 已经为你添加了它们:
{ "expo": { "plugins": ["expo-secure-store", "@clerk/expo"] } }
@clerk/expo 插件会添加 Apple 登录 entitlement(如果应用不使用 Apple 登录,可以通过插件选项 appleSignIn: false 将其禁用)、为托管身份验证回调注册 Android intent filter,并应用底层 clerk-android SDK 所需的 Android 打包修复。如果你使用原生使用 Google 登录的按钮,还需要将 @clerk/expo-google-signin 插件一并添加。
托管身份验证会根据应用配置中的 android.package 和 ios.bundleIdentifier 值生成默认回调。在创建生产构建版本之前,请在 Clerk Dashboard 的 Native applications 页面添加应用,并使用相同的 Android package name 和 iOS bundle identifier,因为生产实例会根据已注册的值验证回调。
3
添加你的 Clerk Publishable Key
从 Clerk Dashboard 的 API keys 页面复制你的 Publishable Key,然后将其添加到项目根目录的 .env 文件中:
EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_your-key-here
必须使用 EXPO_PUBLIC_ 前缀,因为 Expo 会在构建时内联这些值,从而使它们可在 JavaScript bundle 中使用。Clerk 的 Publishable Key 可以安全公开。不要 将 Secret Keys 放在 EXPO_PUBLIC_ 前缀之后。
4
将你的应用包装在 <ClerkProvider> 中
在根布局文件中(使用 Expo Router 时为 src/app/_layout.tsx),将应用包装在 <ClerkProvider> 中并传入 Publishable Key。建议显式传入 tokenCache:
import { ClerkProvider } from '@clerk/expo'; import { tokenCache } from '@clerk/expo/token-cache'; import { Slot } from 'expo-router'; const publishableKey = process.env.EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY!; if (!publishableKey) { throw new Error('将你的 Clerk Publishable Key 添加到 .env 文件中'); } export default function RootLayout() { return ( <ClerkProvider publishableKey={publishableKey} tokenCache={tokenCache}> <Slot /> </ClerkProvider> ); }
在 Core 3 中,Expo 应用的 <ClerkProvider> 需要 publishableKey。生产环境的 React Native 构建中,node_modules 内部的环境变量不会被内联,因此必须显式传入该属性。
来自 @clerk/expo/token-cache 的 tokenCache 使用 expo-secure-store 持久化用户会话,以便在应用重启后仍能保留。显式传入它可以让依赖关系更清晰,并且以后也能轻松替换为自定义缓存实现。
添加身份验证
下一步取决于你选择的方式。下面的选项卡展示了每种方式所需的最少代码。
托管身份验证会在应用上方的浏览器身份验证会话中打开 Clerk 的账户门户。用户可以完成 Clerk 应用中启用的任意登录或注册方式,SDK 会在应用中激活生成的会话。调用 useHostedAuth() hook 中的 startHostedAuth():
import { useAuth } from '@clerk/expo'; import { useHostedAuth } from '@clerk/expo/hosted-auth'; import { ActivityIndicator, Button, Text, View } from 'react-native'; export default function MainScreen() { const { isLoaded, isSignedIn } = useAuth(); const { startHostedAuth } = useHostedAuth(); const handleSignUp = async () => { try { await startHostedAuth({ mode: 'sign-up' }); } catch (error) { // 在应用中处理错误 } }; if (!isLoaded) { return <ActivityIndicator size="large" />; } return ( <View> {isSignedIn ? ( <Text>You're signed in</Text> ) : ( <Button title="Sign up" onPress={handleSignUp} /> )} </View> ); }
身份验证完成后,SDK 会关闭浏览器会话、激活新会话,并使用已登录状态更新 useAuth()。浏览器不会保留单独的活动会话。
startHostedAuth() 默认打开登录页面,并接受 mode: 'sign-in' | 'sign-up'。如果用户在完成身份验证前关闭浏览器,它会以 createdSessionId 为 null 的结果解决;身份验证失败时则会抛出异常。
这种方式可以在 Expo Go 中运行,此时 Expo 会提供开发回调。在开发构建或生产构建中,回调会根据你的 iOS bundle identifier 或 Android package name 生成,因此请将 @clerk/expo 配置插件保留在应用配置中,并在修改任一标识符后重新构建原生项目。
账户门户运行在浏览器中,因此社交登录使用各提供商的 Web OAuth 流程,而不是原生流程。请参阅托管身份验证指南,了解生产凭证要求和故障排除方法。
<AuthView /> 会渲染完整的原生登录和注册界面,支持电子邮件、电话、通行密钥、多因素身份验证,以及 Clerk Dashboard 中启用的任何社交连接。它会以内联方式渲染在 React Native 视图层级中,因此你可以将其放置在模态框、路由或全屏视图中。下面的示例会在模态框中打开它:
import { useAuth } from '@clerk/expo'; import { AuthView, UserButton } from '@clerk/expo/native'; import { useState } from 'react'; import { ActivityIndicator, Button, Modal, View } from 'react-native'; export default function MainScreen() { const { isLoaded, isSignedIn } = useAuth({ treatPendingAsSignedOut: false }); const [isAuthOpen, setIsAuthOpen] = useState(false); if (!isLoaded) { return <ActivityIndicator size="large" />; } return ( <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}> {isSignedIn ? <UserButton /> : <Button title="Sign up" onPress={() => setIsAuthOpen(true)} />} <Modal animationType="slide" visible={isAuthOpen} presentationStyle="pageSheet" onRequestClose={() => setIsAuthOpen(false)}> <AuthView onDismiss={() => setIsAuthOpen(false)} /> </Modal> </View> ); }
用户登录后,原生会话会同步回 JavaScript SDK,因此 useAuth() 和 useUser() 会反映已登录状态。向 useAuth() 传入 treatPendingAsSignedOut: false,这样待处理的会话任务就不会被视为已登出。
将包含<AuthView />的<Modal>与已登录和已登出内容保持在同一层级并挂载。如果只在已登出内容中渲染它,身份验证状态可能会在会话任务仍处于待处理状态时发生变化,而条件渲染会过早卸载模态框。
<AuthView /> 接受 mode="signIn" | "signUp" | "signInOrUp"(默认值)、用于控制原生关闭按钮的 isDismissible 布尔值,以及 onDismiss 回调。当用户必须先完成身份验证才能继续时,请将其作为全屏视图渲染,并设置 isDismissible={false},而不是放在模态框中。
<UserButton /> 不接受任何 props。它会显示已登录用户的头像或姓名首字母,点击后打开原生 <UserProfileView />,用户可以在其中管理个人信息、安全设置并登出。
<AuthView /> 会自动显示 Clerk Dashboard 中启用的所有社交连接对应的登录按钮,并在内部处理相关流程,因此你不需要 expo-crypto 或原生登录 hooks。原生 OAuth 仍然需要在 Clerk Dashboard 和各提供商控制台中配置凭证。否则,按钮会显示,但点击后会失败。请按照本页面底部链接中的 Clerk 使用 Google 登录和使用 Apple 登录指南进行操作。
这种方式需要开发构建版本,因为这些组件由原生模块支持:
# 在本地运行开发构建版本- npx expo run:android- npx expo run:ios# 或使用 EAS 构建- eas build --platform ios --profile development使用 Core 3 hooks 构建你自己的界面。这种方式可以在 Expo Go 中运行。下面的示例使用 useSignUp() 构建一个带有电子邮件验证码验证的电子邮件和密码注册表单:
import { useAuth, useSignUp } from '@clerk/expo'; import { useState } from 'react'; import { Button, Text, TextInput, View } from 'react-native'; export default function MainScreen() { const { isLoaded, isSignedIn } = useAuth(); const { signUp } = useSignUp(); const [emailAddress, setEmailAddress] = useState(''); const [password, setPassword] = useState(''); const [code, setCode] = useState(''); const [isVerifying, setIsVerifying] = useState(false); const handleSignUp = async () => { const { error } = await signUp.password({ emailAddress, password }); if (error) { console.error(JSON.stringify(error, null, 2)); return; } const { error: sendError } = await signUp.verifications.sendEmailCode(); if (sendError) { console.error(JSON.stringify(sendError, null, 2)); return; } setIsVerifying(true); }; const handleVerify = async () => { const { error } = await signUp.verifications.verifyEmailCode({ code }); if (error) { console.error(JSON.stringify(error, null, 2)); return; } await signUp.finalize(); }; if (!isLoaded) { return null; } if (isSignedIn) { return <Text>You're signed in</Text>; } if (isVerifying) { return ( <View> <TextInput value={code} placeholder="Enter your verification code" onChangeText={setCode} keyboardType="numeric" /> <Button title="Verify" onPress={handleVerify} /> </View> ); } return ( <View> <TextInput autoCapitalize="none" value={emailAddress} placeholder="Enter email" onChangeText={setEmailAddress} keyboardType="email-address" /> <TextInput value={password} placeholder="Enter password" secureTextEntry onChangeText={setPassword} /> <Button title="Sign up" onPress={handleSignUp} /> {/* Expo Web 注册流程必需。Clerk 会在 Android 和 iOS 上跳过浏览器 CAPTCHA */} <View nativeID="clerk-captcha" /> </View> ); }
在 Core 3 中,signUp.password() 和 signUp.verifications.verifyEmailCode() 等方法会返回 { error },而不是在验证错误时抛出异常。验证完成注册后,signUp.finalize() 会将其转换为活动会话,并使用已登录状态更新 useAuth()。
对应的登录流程使用 useSignIn(),其中 finalize() 接受一个 navigate 回调,以便你在重定向前处理会话任务:
import { useSignIn } from '@clerk/expo'; import { type Href, useRouter } from 'expo-router'; export default function SignInScreen() { const { signIn } = useSignIn(); const router = useRouter(); const handleSignIn = async (emailAddress: string, password: string) => { const { error } = await signIn.password({ emailAddress, password }); if (error) { return; } if (signIn.status === 'complete') { await signIn.finalize({ navigate: ({ session, decorateUrl }) => { if (session?.currentTask) return; // 让会话任务层来处理 router.replace(decorateUrl('/') as Href); }, }); } }; // ... render your email and password fields }
要在自定义界面中添加原生使用 Google 登录和使用 Apple 登录的按钮,请分别使用来自 @clerk/expo/google 的 useSignInWithGoogle() hook 和来自 @clerk/expo/apple 的 useSignInWithApple() hook。两者都会返回一个启动方法(startGoogleAuthenticationFlow() 和 startAppleAuthenticationFlow()),该方法会以 { createdSessionId, setActive } 解决。
这两个 hooks 都使用原生模块,因此需要开发构建版本以及安装步骤中的相关包。useSignInWithGoogle() 还需要 @clerk/expo-google-signin 配置插件。在 iOS 上,App Store 指南 4.8 要求任何提供第三方社交登录的应用同时提供使用 Apple 登录。请按照本页面底部链接中的 Clerk 指南,在 Clerk Dashboard 和各提供商控制台中注册凭证。
读取已登录用户
在应用的任何位置,使用 useUser() 和 useAuth() 读取用户数据,再加上 <Show> 和 useClerk() 来保护内容并执行登出:
import { Show, useClerk, useUser } from '@clerk/expo'; import { Link } from 'expo-router'; import { Pressable, Text, View } from 'react-native'; export default function HomeScreen() { const { user } = useUser(); const { signOut } = useClerk(); return ( <View> <Show when="signed-in"> <Text>你好,{user?.firstName ?? 'friend'}</Text> <Pressable onPress={() => signOut()}> <Text>登出</Text> </Pressable> </Show> <Show when="signed-out"> <Link href="/(auth)/sign-in"> <Text>登录</Text> </Link> </Show> </View> ); }
<Show> 取代了该 SDK 早期版本中的旧 <SignedIn>、<SignedOut> 和 <Protect> 组件。它还支持 when={{ role: '...' }}、when={{ permission: '...' }} 以及其他授权谓词。
运行应用
对于托管身份验证和自定义流程,请运行以下命令,然后在 Expo Go 中打开项目:
- npx expo start- npx expo run:android- npx expo run:ios后续步骤
逐步说明如何设置三种集成方式,并提供 GitHub 上的配套仓库。
使用 Clerk 的账户门户在 Expo 应用中为用户完成登录和注册,并了解回调、取消处理和生产环境设置。
AuthView、UserButton 和 UserProfileView 的 API 参考,包括配置、主题和平台要求。
通过 Clerk Dashboard 和 Google Cloud Console 为 Android 和 iOS 设置原生使用 Google 登录。
配置原生 Apple 登录,以满足 App Store 指南 4.8。
在你的 Expo 应用中使用 Clerk 的 hooks 和 Show 组件来保护路由并访问用户数据。
配置生产凭证、允许移动端 SSO 重定向,并使用 EAS Build 发布。