使用关联帐户的 Apple Security 登录
Sign in with Apple Security for Linked Account
假设您在网络平台上有一个现有用户 management/database。应该集成使用 Apple 登录以加快登录和注册过程——尽管它总是会创建一个链接到电子邮件地址的常规帐户(只是没有常规密码)。 使用 Apple 提供的(经过验证的)JWT 进行身份验证是否安全?
登录(现有帐户)需要以下步骤:
- 用户在应用程序中点击“使用 Apple 登录”
- Apple 生成的 JWT 发送到认证服务器
- 服务器使用 Apple 的 API 端点
提供的 public 密钥验证 JWT
- 服务器从(已验证的)JWT 中提取电子邮件,如果存在拥有该电子邮件的用户,则该用户已登录(API returns 内部 access/refresh 令牌会话)
我尝试为 iOS 个应用编写答案。不过先把问题弄清楚:
“使用 Apple 提供的(经过验证的)JWT 进行身份验证是否安全?”
我们从授权任务中收到的唯一已知 JWT 是“id_token”。其他参数也可能是 JWT,但这些对客户端来说是不透明的。
现在的问题是,如果我们将 id_token 发送到应用服务器,仅验证 id_token 是否足以向客户端分发应用服务器域的访问令牌?答:不!
当使用 Apple 的 iOS 身份验证框架进行 Apple 登录时,授权任务 returns 完成处理程序中的 ASAuthorization
值。这基本上包含以下参数:
user
: 一个标识符
identityToken
:JWT“id_token”(参见 OIDC)
authorizationCode
:一种短暂的一次性有效令牌,为应用程序的服务器组件提供授权证明。使用授权请求中传递的状态属性将授权代码绑定到特定事务。应用程序的服务器组件可以使用为此目的提供的 Apple 身份服务端点验证代码。 *)
*) 如果该值确实对应于客户端将通过 “前端通道” 又名用户代理又名浏览器获得的 OIDC“代码”值,那么我们还应确保有一个额外的机制实际上 提供安全的“授权证明”(通用链接,PKCE),参见Authorization Code Interception Attack。
如果这些攻击在技术上是不可能的,因为身份验证系统提供了与应用程序的安全通信通道,但是我们不需要 PKCE。
id_token 包含有关已通过身份验证的用户的信息,这些信息存储在 Provider 上。这是一个签名的 JWT。即使可以成功验证 JWT,单独使用 JWT 应用服务器也无法确定发送者就是它所认为的那个人。我们不想给任何人未经身份验证的访问令牌!
应用服务器需要更多证明,这将通过 authorizationCode
参数来完成。不过,此检查必须在提供程序上完成。
So, we have to perform two steps:
Verify the Identity Token (id_token)
这将在应用服务器上执行。
验证授权码
第二步将由您的应用服务器 obtaining a refresh token 形成提供商特殊端点来完成。
通过第 2 步,我们收到 TokenResponse。
如果成功,我们将收到访问令牌和刷新令牌。访问令牌没有用,但我们需要刷新令牌:
“您最多可以每天验证一次刷新令牌,以确认用户在该设备上的 Apple ID 在 Apple 的服务器上仍然处于良好状态。”
将此存储在您的应用程序服务器上。
在您的应用服务器上完成所有操作后,您可以继续:
管理用户会话
验证身份令牌后,您的应用程序负责管理用户会话。您可以将会话的生命周期与 Apple 设备上成功的 getCredentialState(forUserID:completion:) 调用联系起来。这是一个本地、廉价、非网络呼叫,由 Apple ID 系统启用,该系统使设备上的 Apple ID 状态与 Apple 服务器保持同步。
“用户会话”可能需要特定于域的访问令牌和刷新令牌。当客户端需要您的令牌端点上的新访问令牌时,您可能会再次验证 Apple 的刷新令牌。
因此,最后一步是您的应用向您的客户端发送特定于域的访问令牌和刷新令牌。
假设您在网络平台上有一个现有用户 management/database。应该集成使用 Apple 登录以加快登录和注册过程——尽管它总是会创建一个链接到电子邮件地址的常规帐户(只是没有常规密码)。 使用 Apple 提供的(经过验证的)JWT 进行身份验证是否安全?
登录(现有帐户)需要以下步骤:
- 用户在应用程序中点击“使用 Apple 登录”
- Apple 生成的 JWT 发送到认证服务器
- 服务器使用 Apple 的 API 端点 提供的 public 密钥验证 JWT
- 服务器从(已验证的)JWT 中提取电子邮件,如果存在拥有该电子邮件的用户,则该用户已登录(API returns 内部 access/refresh 令牌会话)
我尝试为 iOS 个应用编写答案。不过先把问题弄清楚:
“使用 Apple 提供的(经过验证的)JWT 进行身份验证是否安全?”
我们从授权任务中收到的唯一已知 JWT 是“id_token”。其他参数也可能是 JWT,但这些对客户端来说是不透明的。
现在的问题是,如果我们将 id_token 发送到应用服务器,仅验证 id_token 是否足以向客户端分发应用服务器域的访问令牌?答:不!
当使用 Apple 的 iOS 身份验证框架进行 Apple 登录时,授权任务 returns 完成处理程序中的 ASAuthorization
值。这基本上包含以下参数:
user
: 一个标识符identityToken
:JWT“id_token”(参见 OIDC)authorizationCode
:一种短暂的一次性有效令牌,为应用程序的服务器组件提供授权证明。使用授权请求中传递的状态属性将授权代码绑定到特定事务。应用程序的服务器组件可以使用为此目的提供的 Apple 身份服务端点验证代码。 *)
*) 如果该值确实对应于客户端将通过 “前端通道” 又名用户代理又名浏览器获得的 OIDC“代码”值,那么我们还应确保有一个额外的机制实际上 提供安全的“授权证明”(通用链接,PKCE),参见Authorization Code Interception Attack。 如果这些攻击在技术上是不可能的,因为身份验证系统提供了与应用程序的安全通信通道,但是我们不需要 PKCE。
id_token 包含有关已通过身份验证的用户的信息,这些信息存储在 Provider 上。这是一个签名的 JWT。即使可以成功验证 JWT,单独使用 JWT 应用服务器也无法确定发送者就是它所认为的那个人。我们不想给任何人未经身份验证的访问令牌!
应用服务器需要更多证明,这将通过 authorizationCode
参数来完成。不过,此检查必须在提供程序上完成。
So, we have to perform two steps:
Verify the Identity Token (id_token) 这将在应用服务器上执行。
验证授权码
第二步将由您的应用服务器 obtaining a refresh token 形成提供商特殊端点来完成。
通过第 2 步,我们收到 TokenResponse。
如果成功,我们将收到访问令牌和刷新令牌。访问令牌没有用,但我们需要刷新令牌:
“您最多可以每天验证一次刷新令牌,以确认用户在该设备上的 Apple ID 在 Apple 的服务器上仍然处于良好状态。”
将此存储在您的应用程序服务器上。
在您的应用服务器上完成所有操作后,您可以继续:
管理用户会话
验证身份令牌后,您的应用程序负责管理用户会话。您可以将会话的生命周期与 Apple 设备上成功的 getCredentialState(forUserID:completion:) 调用联系起来。这是一个本地、廉价、非网络呼叫,由 Apple ID 系统启用,该系统使设备上的 Apple ID 状态与 Apple 服务器保持同步。
“用户会话”可能需要特定于域的访问令牌和刷新令牌。当客户端需要您的令牌端点上的新访问令牌时,您可能会再次验证 Apple 的刷新令牌。
因此,最后一步是您的应用向您的客户端发送特定于域的访问令牌和刷新令牌。