EasyStarter logoEasyStarter

认证服务

配置 Better Auth、Google OAuth 和 Apple 原生登录

认证服务

EasyStarter 移动端使用 Better Auth 作为认证方案,当前已经内置:

  • 邮箱 + 密码登录
  • Google OAuth 登录
  • Apple 原生登录(仅 iOS)

服务端配置位于 apps/server/src/lib/auth.ts。Apple 登录使用原生 ID Token 流程:App 调用系统级 Apple 登录弹窗,拿到 identityToken 后直接传给 Better Auth 验证,无需网页跳转。

所需环境变量

Server 端

BETTER_AUTH_SECRET=
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
APPLE_APP_BUNDLE_IDENTIFIER=

获取 BETTER_AUTH_SECRET

BETTER_AUTH_SECRET 用于 Better Auth 签名和加密会话数据,必须是一个足够长的随机字符串。

openssl rand -base64 32

复制生成结果,分别填到本地和生产环境:

apps/server/.dev.vars
BETTER_AUTH_SECRET=your-long-random-secret
apps/server/.env.production
BETTER_AUTH_SECRET=your-long-random-secret

创建 Google OAuth Client

Google Cloud 控制台:Google Cloud Console

  1. 登录 Google Cloud Console,选择或新建项目
  2. 进入 APIs & Services > Credentials
  3. 点击 Create Credentials → 选择 OAuth client ID
  4. 如需要,先完成 OAuth consent screen 配置
  5. 应用类型选择 Web application
  6. 填写回调地址

关键字段:

  • Authorized JavaScript origins:你的前端地址,例如 https://yourdomain.com
  • Authorized redirect URIs{SERVER_URL}/api/auth/callback/google

移动端 Google OAuth 需要 HTTPS 回调地址,推荐用 ngrok 将本地服务端映射为 HTTPS。

为什么移动端必须用 ngrok?

移动端的 Google 登录走的是 深链(Deep Link)回调流程,而不是浏览器页面跳转:

  1. App 调用 expo-web-browser 打开 Google 登录页
  2. 用户完成登录后,Google 将请求重定向到服务端回调地址(SERVER_URL/api/auth/callback/google
  3. 服务端处理完成后,将用户重定向回 App 的 Deep Link(例如 myapp://callback
  4. 操作系统拦截这个 Deep Link,唤起 App,完成登录

这个流程有两个限制:

  • Google OAuth 强制要求 HTTPShttp://localhost 不被接受
  • 真机和模拟器无法直接访问开发机的 localhost——服务端必须有一个从外部可达的地址

ngrok 解决了这两个问题:它将本地的 localhost:3001 暴露为一个公网可访问的 HTTPS 地址,Google 可以成功回调,服务端也能把用户导回 App 的 Deep Link。

安装 ngrok

前往 ngrok 官网 下载并安装,或使用 Homebrew:

brew install ngrok

安装后注册账号并完成认证:

ngrok config add-authtoken YOUR_AUTH_TOKEN

Auth Token 在 ngrok Dashboard → Your Authtoken 中获取。

启动隧道

在启动本地服务端(pnpm dev:server)之后,再开一个终端运行:

ngrok http 3001

ngrok 会输出一个 HTTPS 地址,类似:

Forwarding  https://xxxx-xxxx.ngrok-free.app -> http://localhost:3001

将这个地址作为 Google OAuth 回调填写:

https://xxxx-xxxx.ngrok-free.app/api/auth/callback/google

同时将 .dev.vars 中的 SERVER_URL 也改为这个 ngrok 地址,确保 Better Auth 的 baseURL 和 OAuth 回调一致。

注意:免费版 ngrok 每次重启都会生成新地址,需要同步更新 Google Cloud Console 的回调 URI 和本地 .dev.vars

创建完成后你会拿到:

  • Client ID → 对应 GOOGLE_CLIENT_ID
  • Client Secret → 对应 GOOGLE_CLIENT_SECRET

配置 Apple 原生登录

移动端 Apple 登录走的是 iOS 系统级原生流程,App 调用 expo-apple-authentication 获取 Identity Token,服务端用 Bundle ID(即 APPLE_APP_BUNDLE_IDENTIFIER)作为 audience 验证 token。

参考:Better Auth Apple 文档

为 App ID 启用 Sign In with Apple

配置 app.json 一章中已创建好 App ID,现在为它开启 Apple 登录能力:

  1. 登录 Apple Developer Portal → Identifiers
  2. 找到并点击你的 App ID
  3. 在 Capabilities 中勾选 Sign In with Apple
  4. 点击 Continue → Save

创建并配置 Service ID

  1. Identifiers 中点击 +,选择 Service IDs → Continue
  2. 填写 Description 和 Identifier(例如 com.yourcompany.yourapp.si),这个值作为 APPLE_CLIENT_ID
  3. 点击 Register 完成创建
  4. 在列表中点击刚创建的 Service ID → 勾选 Sign In with Apple → 点击 Configure
  5. Primary App ID 中选择你的 App ID
  6. 配置 Domains and SubdomainsReturn URLs
环境Domains and SubdomainsReturn URLs
开发xxxx-xxxx.ngrok-free.apphttps://xxxx-xxxx.ngrok-free.app/api/auth/callback/apple
生产server.yourdomain.comhttps://server.yourdomain.com/api/auth/callback/apple

开发环境使用 ngrok 地址,每次 ngrok 重启后需要同步更新这里的 Domain 和 Return URL。生产环境填写你的实际服务端域名。

  1. 点击 Next → Done → Continue → Save

填入环境变量

本地开发统一放到 apps/server/.dev.vars

apps/server/.dev.vars
BETTER_AUTH_SECRET=your-long-random-secret
GOOGLE_CLIENT_ID=your-google-client-id
GOOGLE_CLIENT_SECRET=your-google-client-secret
APPLE_APP_BUNDLE_IDENTIFIER=com.yourcompany.yourapp

生产部署时,敏感值放到 apps/server/.env.production

apps/server/.env.production
BETTER_AUTH_SECRET=your-long-random-secret
GOOGLE_CLIENT_SECRET=your-google-client-secret

将非敏感的 ID 类变量填到 apps/server/wrangler.jsoncvars 中:

apps/server/wrangler.jsonc
"vars": {
  "GOOGLE_CLIENT_ID": "your-google-client-id",
  "APPLE_APP_BUNDLE_IDENTIFIER": "com.yourcompany.yourapp"
}

Better Auth 在移动端的作用

移动端的 authClient 配置在 apps/native/lib/auth/auth.client.ts,通过 @better-auth/expo 适配器处理 deep link 回调和 cookie 存储。

当前已支持:

  • 邮箱密码注册和登录
  • Google OAuth(通过 deep link 回调)
  • Apple 原生登录(通过 ID Token,仅 iOS)
  • 基于 Cookie 的跨端会话管理

Apple 登录仅在真机和 TestFlight 环境中可用,模拟器不支持。