要在 Capacitor 应用中添加身份验证,请选择一个身份源(您自己的后端、Firebase、Supabase 或 Neon 等托管服务、Auth0、Okta 或 Entra ID 等 OIDC 提供商,或者 Better Auth 等自托管库),使用 native plugins 处理任何打开提供商登录页面的操作,在服务器上验证 token,并将生成的 session 存储在 Keychain 或 Keystore 中。随后,通过生物识别和 passkeys 可以实现快速二次登录。
本指南将每种常见选项映射到正确的 Capacitor plugin 和流程,并针对所有应用通用的部分(即登录调用、token 验证、session 存储和生物识别解锁)提供 code。内容已更新至 2026 年 10 月的 Capacitor 8 版本。下方链接了各提供商的具体分步指南。
每个 Capacitor 应用最终都会采用的身份验证流程
无论您选择哪个提供商,其核心逻辑都是一致的:
- 识别 用户:通过 native social sheet、系统浏览器中的提供商登录页、passkey prompt 或提交邮箱密码的表单。
- 获取凭证: 即 ID token、授权 code 或来自身份验证服务器的 session token。
- 在服务器端进行验证:验证签名、发行者、受众和有效期,然后创建或查找用户。
- 签发会话:使用你自己的 token 或提供商的 token,并制定刷新策略。
- 安全存储 在设备上,并将其附加到 API 调用中。
- 快速解锁 下次使用生物识别技术,并处理注销和账号删除。
步骤 1 和 2 会随提供商而异。除了完全托管的 BaaS(由 SDK 处理大部分工作)外,步骤 3 到 6 在所有方案中都是你的职责。
为什么 WebView 登录页面会失效
Capacitor 应用在 WKWebView (iOS) 或 Android WebView 中运行你的 Web code,并具有本地 Origin(capacitor://localhost 或 https://localhost)。在 WebView 中加载提供商的登录页面会导致三个问题:
- Google 会返回
disallowed_useragent并拒绝显示该页面。 - 由于 App 无法证明该页面是真实的提供商,因此 RFC 8252 建议原生 App 使用系统浏览器。
- 全页重定向会脱离你的 bundled app,并导致状态丢失。
因此,以下每种流程都会使用原生 SDK (Apple, Google, Facebook) 或系统浏览器会话(ASWebAuthenticationSession iOS 上为 Safari,Android 上为 Chrome Custom Tabs),并通过自定义 scheme 返回 App。
方案概览
| 方案 | 最适合 | Capacitor 插件 | 后端工作 | 指南 |
|---|---|---|---|---|
| 通过 Apple 登录 | 任何集成第三方登录的 iOS App | @capgo/capacitor-social-login |
验证 ID token | Apple 指南 |
| Google 登录 | 消费者应用,Android 优先 | @capgo/capacitor-social-login |
验证 ID token | Google 指南 |
| Auth0 | 支持多种连接的托管登录 | @capgo/capacitor-social-login (OAuth2) |
验证 access token | Auth0 指南 |
| Okta | 员工身份与 B2B SSO | @capgo/capacitor-social-login (OAuth2) |
验证 access token | Okta 指南 |
| Microsoft Entra ID | Microsoft 365 组织 | @capgo/capacitor-social-login (OAuth2) |
验证 Access Token, Graph | Entra ID 指南 |
| 更好的身份验证 | 自托管,自主掌控用户数据库 | better-auth 客户端 + Social Login |
运行 Better Auth 服务端 | Better Auth 指南 |
| Supabase Auth | 内置身份验证的 Postgres 后端 | 社交登录 + supabase-js |
极小 | Supabase 指南 |
| Neon Auth | 集成托管 Better Auth 的 Neon Postgres | @capgo/capacitor-neon |
极小 | Neon 插件文档 |
| Firebase Authentication | 已使用 Firebase 的应用 | @capgo/capacitor-firebase-authentication |
极小 | Firebase 文档 |
| Passkeys | 在自有域名实现无密码登录 | @capgo/capacitor-passkey |
WebAuthn 服务器 | Passkey 文档 |
| 邮箱和密码 | 简单应用,自有后端 | 无 (HTTP) | 哈希、重置、速率限制 | 本文 |
原生社交登录 (Apple, Google, Facebook)
一个插件即可覆盖三大主流消费级提供商,并内置通用 OAuth2 引擎:
bun add @capgo/capacitor-social-login
bunx cap sync
import { SocialLogin } from '@capgo/capacitor-social-login';
await SocialLogin.initialize({
apple: { clientId: 'com.example.app' },
google: {
webClientId: 'WEB_CLIENT_ID.apps.googleusercontent.com',
iOSClientId: 'IOS_CLIENT_ID.apps.googleusercontent.com',
},
});
const { result } = await SocialLogin.login({ provider: 'google', options: {} });
// send result.idToken to your server
在以下设置中关闭不使用的提供商: capacitor.config.ts (plugins.SocialLogin.providers) 这样它们的 SDK 就不会被编译进 App 中。如果你不使用 Facebook,这还会移除 Facebook SDK 的广告 ID 权限。
每个 provider 都有原生配置:Apple 需要在 Xcode 中开启 Capability,并为 Android 配置 Services ID;Google 需要 SHA-1 指纹和反向的 Client ID URL scheme。这些 Apple 以及 Google 指南会讲解每个步骤和常见错误。
基于 OAuth 2.0 和 OpenID Connect 的企业 SSO
对于 Auth0、Okta、Microsoft Entra ID、Keycloak、Cognito、OneLogin 或你自己的 OIDC 服务器,请使用插件的 oauth2 provider。它通过 PKCE 运行授权 code 流程,在 ASWebAuthenticationSession iOS 上以及 Android 的 Custom Tabs 中,当你设置 androidUseCustomTabs: true:
await SocialLogin.initialize({
oauth2: {
corp: {
issuerUrl: 'https://sso.example.com/realms/mobile', // OIDC discovery
clientId: 'mobile-app',
redirectUrl: 'com.example.app://oauth/corp',
scope: 'openid profile email offline_access',
pkceEnabled: true,
androidUseCustomTabs: true,
},
},
});
const { result } = await SocialLogin.login({
provider: 'oauth2',
options: { providerId: 'corp' },
});
你可以在同一个 map 中注册多个 provider,并选择其中一个 providerId,这正是多租户 B2B 应用让每个客户自带 IdP 的方式。该插件还会处理刷新 (SocialLogin.refresh), 并支持注销: id_token_hint以及兼容 Ionic Auth Connect 的封装层 (SocialLoginAuthConnect),方便从 Auth Connect 迁移的团队。各服务商指南: Auth0, Okta, Entra ID。关于协议背景,请参阅 在 Capacitor 应用中实现 OAuth2 的 5 个步骤.
托管后端:Firebase、Supabase 和 Neon
如果你的数据已存储在 Firebase、Supabase 或 Neon 中,请直接使用它们的 auth,这样无需额外开发即可实现安全规则和行级安全性(RLS)。
- Supabase:通过 Social Login 插件获取 ID token 并调用
supabase.auth.signInWithIdToken({ provider: 'google', token })。Supabase 会验证该 token 并返回 session。完整配置如下: 使用 Capacitor Social Login 的 Supabase. - Neon: Neon Auth 是运行在你的 Neon 分支上的托管版 Better Auth。
@capgo/capacitor-neon支持通过系统浏览器使用邮箱密码、邮箱 OTP、Google、GitHub 或 Vercel 进行原生登录。它会返回一个用于 Neon Data API 的 JWT,因此行级安全性(row-level security)同样适用。完整配置如下: Neon 插件文档. - Firebase:你可以选择使用
@capgo/capacitor-firebase-authentication,它封装了原生的 Firebase Auth SDK;或者通过 Social Login 获取 ID token,然后在 JS SDK 中据此创建 Firebase 凭据。详情请参阅 Firebase Google 登录文档.
自托管:Better Auth
Better Auth 是一个开源的 TypeScript 认证库,可将用户信息存储在您自己的数据库中。在您信任应用 origin 并切换到 Bearer Token 后,它即可在 Capacitor 中正常工作,因为跨站 Cookie 在 WKWebView 中并不稳定。社交登录通过原生 plugin 和 ID token 交接完成。具体步骤如下: 如何在 Capacitor 应用中使用 Better Auth.
Passkeys
Passkeys 使用存储在 iCloud Keychain 或 Google Password Manager 中的密钥对来取代密码。这需要您的应用与您的网站域名相关联(apple-app-site-association 在 iOS 上, assetlinks.json 在 Android 上)以及一个 WebAuthn 服务器。
@capgo/capacitor-passkey 让您可以保留标准 WebAuthn code。Relying Party 配置在 capacitor.config.ts,在启动时调用一次 shim,然后 navigator.credentials.create() 以及 .get() 会被路由到原生 Passkey API:
import { CapacitorPasskey } from '@capgo/capacitor-passkey';
await CapacitorPasskey.autoShimWebAuthn();
// existing WebAuthn code keeps working
const assertion = await navigator.credentials.get({
publicKey: requestOptionsFromServer,
});
像 Better Auth 这样的库,以及 Auth0 和 Okta 等托管服务商,都可以充当 WebAuthn 服务器。请参阅 passkey 插件页面.
使用自有后端实现邮箱和密码登录
无需插件,只需 fetch即可实现。工作量主要在服务端:使用 Argon2id 或 bcrypt 进行哈希处理、限制登录尝试频率、发送验证和重置邮件,并支持账号注销。通过 Universal Links 和 App Links 在 App 内打开重置和验证链接,确保链接能准确跳转到手机上的对应位置。除非你有必要完全自主掌控这些逻辑,否则使用 Better Auth 这样的库或托管服务可以在降低风险的同时获得相同的功能。
务必在服务端验证 token
客户端检查可以被绕过。无论使用哪种服务商,服务端在创建 session 之前都必须验证 token:
import { createRemoteJWKSet, jwtVerify } from 'jose';
type IssuerConfig = {
jwks: ReturnType<typeof createRemoteJWKSet>;
issuer: string | string[];
audience: string[];
};
const issuers: Record<'google' | 'apple', IssuerConfig> = {
google: {
jwks: createRemoteJWKSet(new URL('https://www.googleapis.com/oauth2/v3/certs')),
issuer: ['https://accounts.google.com', 'accounts.google.com'],
audience: ['WEB_CLIENT_ID.apps.googleusercontent.com', 'IOS_CLIENT_ID.apps.googleusercontent.com'],
},
apple: {
jwks: createRemoteJWKSet(new URL('https://appleid.apple.com/auth/keys')),
issuer: 'https://appleid.apple.com',
audience: ['com.example.app', 'com.example.app.signin'],
},
};
export async function verifyIdToken(provider: 'google' | 'apple', idToken: string) {
const cfg = issuers[provider];
const { payload } = await jwtVerify(idToken, cfg.jwks, {
issuer: cfg.issuer,
audience: cfg.audience,
});
return payload; // use payload.sub as the stable provider user ID
}
服务商侧的关键用户标识 sub (加上服务商名称),而非邮箱。仅在服务商将其标记为已验证时,才通过邮箱进行账号绑定 (email_verified: true)。Meta 的 Limited Login token 不包含该声明。
请安全地存储会话
localStorage 且 Capacitor Preferences 仅为普通文件。请将长期有效的 token 存放在 Keychain (iOS) 或经过 Keystore 加密的存储中 (Android)。 @capgo/capacitor-native-biometric 有简单的 setData, getData 以及 deleteData 实现方法:
bun add @capgo/capacitor-native-biometric
bunx cap sync
import { NativeBiometric } from '@capgo/capacitor-native-biometric';
export const sessionStore = {
async save(token: string) {
await NativeBiometric.setData({ key: 'session.token', value: token });
},
async load(): Promise<string | null> {
try {
const { value } = await NativeBiometric.getData({ key: 'session.token' });
return value;
} catch {
return null;
}
},
async clear() {
await NativeBiometric.deleteData({ key: 'session.token' }).catch(() => {});
},
};
让 access token 保持短期有效,并通过 refresh token 或服务端 session 刷新。我们的 安全 Token 存储指南 更深入地介绍轮换和撤销。
生物识别:用于解锁,而非身份
Face ID 和指纹只能证明拿着手机的人能解锁设备。用它们来控制对已存储 session 的访问:
import { AccessControl, NativeBiometric } from '@capgo/capacitor-native-biometric';
// after a real login, offer biometric unlock
await NativeBiometric.setData({
key: 'session.refresh',
value: refreshToken,
accessControl: AccessControl.BIOMETRY_ANY,
});
// next app start
const { value } = await NativeBiometric.getSecureData({
key: 'session.refresh',
reason: 'Unlock your account',
});
// exchange `value` with your server for a fresh access token
使用 accessControl 设置后,只有在生物识别检查成功后,OS 才会释放该值,因此保护由 Keychain 或 Keystore 强制执行,而非 JavaScript。配合服务端 session 过期机制使用;对于高风险应用,还应加入 root 和越狱检测。更多内容见 Capacitor 应用中的生物识别认证.
选择分发方式
| 如果你… | 使用 |
|---|---|
| 在 iOS 和 Android 上发布面向消费者的 App | 通过 Social Login 接入 Apple + Google,外加邮箱或 passkeys |
| 面向使用 Microsoft 365 的企业销售 | 通过 OAuth2 provider 接入 Entra ID |
| 每个客户都需要对接多个企业级 IdP | 使用 Auth0 或 Okta 作为 broker,或通过多个 OAuth2 provider providerId |
| 已经在用 Supabase 或 Firebase | 使用其 Auth,通过原生 ID token 登录 |
| 已经在用 Neon | Neon Auth 接入 @capgo/capacitor-neon |
| 想自己掌控用户表,不依赖第三方供应商 | 更好的身份验证 |
| 想要无密码登录 | Passkeys,并提供邮件 magic link 等回退方式 |
| 需要快速重新登录 | 在上述任一方案基础上,通过生物识别解锁已保存的 Session |
影响登录的 App Store 和 Play Store 规则
- Apple 4.8 登录服务:将第三方登录作为主要账号系统时,必须提供同等的隐私保护选项。Sign in with Apple 即可满足。
- Apple 5.1.1(v):创建账号时必须支持应用内账号注销,且应撤销 Sign in with Apple 的 token。请参阅 账号注销合规性.
- Google Play 账号注销: 带有账号功能的 App 必须在 App 内及 Play Console 声明的网页链接中提供注销选项。
- 审核人员访问权限: 为审核人员提供可用的演示账号。如果仅支持 SSO 登录,请提供一个测试租户用户。
- Xcode 26: 自 2026 年 4 月起,App Store Connect 要求使用 Xcode 26 和 iOS 26 SDK 进行构建,因此在提交新增身份验证功能的版本前请务必更新。
安全发布身份验证变更
Auth bugs block every user, so you want to fix them fast. Native changes (entitlements, URL schemes, intent filters) need a store build. Everything in TypeScript, like provider config, scopes, error handling and UI, can be pushed with Capgo 实时更新 并在出现问题时进行回滚。 Capgo 构建 当确实需要发布新的 Native Build 时,可以在云端生成已签名的 iOS 和 Android 二进制文件。
后续步骤
选择您的 provider 并参考相应的指南: