跳转到内容
supastack
浏览文档
WebNext.js

For AI agents: fetch the complete documentation index at /llms.txt, the full documentation corpus at /llms-full.txt, the agent skill at /skill.md, or this page as Markdown at /zh/docs/web/apple-sign-in.md (or send Accept: text/markdown).

添加 Apple 登录

在 Apple Developer 门户中注册 App ID、Services ID 和 Sign in with Apple 密钥,并把客户端凭据对接到应用。

询问本指南
打开方式

初学者演练

前提条件:Web 应用在本地运行(5 分钟启动)、已迁移且能存真实账户的数据库(设置数据库),以及一个 Apple Developer Program 会员——与移动端账户指南注册的同一个每年 99 美元的账户,如果还没完成,先完成那一步再继续。下面开发者门户里的所有操作都不额外收费。

为什么重要:每当 iOS 应用提供 Google 或 GitHub 这类第三方社交登录时,App Store 审核都要求提供 Sign in with Apple;它在 Web 端也是一颗可靠、低摩擦的按钮——Apple 用户用设备上已有的账户即可登录。

快速术语:App ID 是应用的注册标识符(com.yourcompany.yourapp)。Services ID 是 Apple 为 Web 和服务端登录签发的第二个标识符——它就是你的客户端 ID。Return URL 是 Apple 允许把登录用户送回的精确地址——即套件的 Better Auth 回调。密钥是 Apple 只提供一次的 .p8 文件;由你自己把它转换成客户端密钥。

1. 注册一个带 Sign in with Apple 能力的 App ID。2. 注册一个指向它、并持有你的域名和 return URL 的 Services ID。3. 创建 Sign in with Apple 密钥并下载 .p8 文件。4. 把该密钥转换成 client-secret JWT,并设置三个 env 值。

一个实在的限制:Apple 的 return URL 必须是注册域名上的绝对 https:// 地址——localhost 和裸 http 都会被拒绝,所以在裸本地服务器上无法完整走通按钮。请在已部署的 URL 上验证,或把本地服务器放到 https 隧道(如 cloudflared tunnel 或 ngrok)后面,并在测试期间注册隧道域名及其回调。

注册 App ID

1. 打开 developer.apple.com/account,用持有 Developer Program 会员的账户登录。

2. 打开 Certificates, Identifiers & Profiles → Identifiers,点击蓝色 + 按钮。

3. 选择 App IDs → Continue,类型保持 App → Continue。

4. Description:你的产品名。Bundle ID:选择 Explicit,输入反向域名形式 com.yourcompany.yourapp——如果也要发布 iOS 应用,请使用 apps/mobile/app.json 中的 ios.bundleIdentifier,让两个平台共享同一个 App ID。

5. 在能力列表中勾选 Sign in with Apple → Continue → Register。

预期结果:该标识符出现在 Identifiers 列表中,且 Sign in with Apple 能力为启用状态。后续复用这一个 App ID——Services ID 和密钥都会把它作为主力应用来关联。

注册 Services ID 和 return URL

1. 回到 Identifiers,再次点击 +,选择 Services IDs → Continue。

2. Description:类似 yourapp web sign-in。Identifier:再来一个反向域名——惯例是 com.yourcompany.yourapp.web——故意与 App ID 不同。这个 Services ID 就是服务器用于 Web 登录的客户端 ID;请精确复制,然后 Continue → Register。

3. 在列表中选中新建的 Services ID,勾选 Sign in with Apple,点击 Configure。

4. 在对话框中把 Primary App ID 设为上一节的 App ID。在 Website URLs 下添加你的域名(如 yourdomain.com),在 Return URLs 下添加 https://yourdomain.com/api/auth/callback/apple——该路径就是套件的 Better Auth 回调 {APP_URL}/api/auth/callback/apple。Save → Continue → Save。

每个 return URL 都必须是注册域名上的绝对 https:// 地址:localhost、裸 IP 地址和 http 都会被拒绝。本地开发时把应用跑在 https 隧道后面,把隧道域名加进 Services ID,注册 https://<tunnel-domain>/api/auth/callback/apple,并在测试期间把 APP_URL 设为隧道 URL。

预期结果:Services ID 显示 Sign in with Apple → Enabled。如果门户拒绝你的域名,先在账户页面完成域名所有权验证。

创建 Sign in with Apple 密钥

1. 在左侧边栏打开 Keys → +。给密钥起名(如 yourapp sign-in key),勾选 Sign in with Apple,点击 Configure,选择 App ID 作为 Primary App ID → Save → Continue → Register。

2. 在确认页面记下 Key ID,然后点击 Download——.p8 文件只提供一次。弄丢了就吊销该密钥另建一个;Apple 不保存副本。

3. 同时记下你的 Team ID——它印在开发者账户页面右上角、账户名旁边。

预期结果:现在你持有三个值——.p8 文件、一个 Key ID 和你的 Team ID。.p8 文件不要放进 Git:它以你的开发者账户签名。

把值加入应用

套件只期望下面三行——与所有社交提供商相同的 clientId/clientSecret 凭据对。APPLE_CLIENT_ID 是 Services ID(com.yourcompany.yourapp.web),不是 App ID。

Apple 不签发静态客户端密钥,所以 APPLE_CLIENT_SECRET 是你用 Team ID、Key ID 和 .p8 私钥自己签发的 JWT——Better Auth 文档附带了生成它的短脚本。签发的密钥最长有效六个月:设个提醒重新生成并更新 env 值,因为它一过期登录就会失败。绝不要把 .p8 文件内容或裸 Key ID 粘进 env——那里只放生成的 JWT。

客户端密钥和 .p8 文件仅限服务端:绝不能出现在 NEXT_PUBLIC_/EXPO_PUBLIC_ 变量里,也不能提交;生产环境通过托管方的密钥存储设置。编辑后重启开发服务器;env 变更只在启动时读取。

# apps/web/.env.local
AUTH_APPLE_ENABLED=true
APPLE_CLIENT_ID=com.yourcompany.yourapp.web   # the Services ID, not the App ID
APPLE_CLIENT_SECRET=<JWT signed with Team ID + Key ID + .p8>

验证与排错

在 /auth 打开你的 APP_URL——已部署 URL 或 https 隧道——点击 Apple 按钮,用任意 Apple ID(不必是开发者账户)登录,确认回到应用时已登录。

大多数失败是三种混淆之一:Services ID 与 App ID——客户端 ID 必须是用于 Web 登录的 Services ID;return URL 不匹配——回调必须与已注册的 Return URL 完全相等,包括协议、域名和路径;或者客户端密钥过期/无效——重新生成 JWT,它只是签发的令牌,不是 .p8 内容。

在设置 AUTH_APPLE_ENABLED=true 之前,/auth 上的 Apple 选项保持禁用——检查 env 名称并重启。在没有 APPLE_CLIENT_ID 和 APPLE_CLIENT_SECRET 的情况下打开开关会让启动失败并指出缺失的变量。

iOS 应用访问的是同一个后端——在其中也发布 Sign in with Apple,好让 App Store 审核接受其他社交按钮。移动端账户指南解释了审核的关注点。

如果你想继续完成设置,可以阅读《添加 Stripe 支付》。

常见问题

14 个问题

supastack 是什么?

supastack 是用于构建 AI 驱动 SaaS 产品的模块化基础。它把通用基础设施整合在一起,让你专注于产品专属的功能。

它支持 Web 和移动端吗?

支持。supastack 包含 Next.js 与 Expo 应用,作为 Web 与移动端体验的起点。

包含哪些认证方式?

Better Auth 覆盖邮箱/密码、OTP 与社交登录。个人工作区随账户一起开通,产品记录从第一天起就有边界。

AI 是如何支持的?

supastack 包含可配置的多供应商 AI、用量追踪、预算,以及加密的自带密钥(BYOK)支持。

订阅如何处理?

对于基于该套件构建的产品,Stripe 计费、订阅与权限构成付费访问的基础。供应商密钥仅存于服务端。

我的产品专属代码放在哪里?

产品专属功能保留在独立的代码库中,产品通过配置接入 supastack 的基础模块。

supastack 如何定价?

套件为一次性购买、终身更新:单框架 249 美元(限时优惠价,较常规价 349 美元优惠 100 美元),或全框架(Next.js、iOS、Android)499 美元(限时优惠价,较常规价 599 美元优惠 100 美元),每个额外开发者席位 75 美元。套件本身没有订阅。本站结账后通过邮件发送许可证密钥,仓库访问通过 GitHub 邀请授予。

工作区如何界定我的数据?

用户记录按 workspaceId 划定边界。身份、权限、AI 用量、计费事件与审计条目都留在个人工作区边界内。

后台任务如何工作?

Trigger.dev 是明确的任务运行时。JobRunner 契约只承诺 enqueue、status 与 cancel——工作流语义保持 Trigger.dev 专有且显式。

邮件与营销触达有何不同?

事务性邮件覆盖产品工作流,如任务完成通知。冷触达与营销活动属于产品自身的范畴,不在本套件的邮件模块内。

移动端购买如何运作?

移动端已支持 RevenueCat 原生购买和恢复购买,访问权限由服务端验证。发布前需配置商店账户并完成设备测试。Web 计费保持独立。

AI 供应商密钥存放在哪里?

自带密钥凭证经过加密且仅存于服务端。密钥在日志中被脱敏;用量与预算在工作区级别保持可见。

结账支持哪些付款方式?

Stripe 托管结账接受银行卡,在 Stripe 账户启用后还可提供支付宝与微信支付——方便中国买家。钱包授权为异步确认,付款完成后许可证页面会立即更新。

我能申请退款吗?

获得代码仓库访问权限后,supastack 将永久归你所有,因此无法退款。但请放心,你将获得包含终身更新的完整源代码,可为你自己或客户构建并发布无限数量的产品。你只需注意不能转卖代码,也不能将仓库作为启动模板二次分发。

CN
主题