ios - Sign in with Apple (iOS App + Backend verification) API 返回错误 "invalid_client"

标签 ios oauth jwt apple-id sign-in-with-apple

我正在尝试使用 iOS 应用程序和后端实现使用 Apple 登录。目标是这样的:

  1. 用户登录 iOS 应用
  2. 在收到肯定响应后,应用会调用后端的端点并移交authorizationCode
  3. 后端现在需要通过对苹果服务器的另一个调用来验证authorizationCode

这里我很困惑。为了进行这个调用,后端需要提供一堆参数:

网址

https://appleid.apple.com/auth/token

查询参数

client_id     = com.mycompany.appname
client_secret = ...
code          = ... // `authorizationCode` from the signin in the iOS app
grant_type    = authorization_code

我已经为 client_secret 生成了一个 JWT:

JWT 属性

header:
    kid: <key id, created on Apple Dev Portal>
claims:
    iss: <team id>
    iat: <current timestamp>
    exp: <current timestamp + 180 days>
    aud: "https://appleid.apple.com"
    sub: "com.mycompany.appname"

昨天我在 Dev Portal 上为两个应用程序(A 和 B)创建了两个 key ,用它来生成 secret ,今天应用程序 A 工作了,我得到了积极的回应:

正面回应

{
    "access_token" : "a1e64327924yt49f5937d643e25a48b81.0.mxwz.GN9TjJIJ5_4dR6WjbZoVNw",
    "token_type" : "Bearer", 
    "expires_in" : 3600, 
    "refresh_token" : "rca76d9ebta644fde9edba269c61eeb41.0.mxwz.sMDUlXnnLLUOu2z0WlABoQ", 
    "id_token" : "eyJraWQiOiJBSURPUEsxIcccYWxnIjoiUlMyNTYifQ.eyJpc3MiOiJodHRwczovL2FwcGxlaWQuYXBwbGUuY29tIiwiYXVkIjoiZGUudHJ1ZmZscy5hcHBsZS1zaWduaW4tdGVzdCIsImV4cCI6MTU2NzcwMDI0MiwiaWF0IjoxNTY3Njk5NjQyLCJzdWaaaiIwMDA3NjkuYWY3NDdjMTlmZGRmNDJhNjhhYmFkZjhlNTQ1MmY3NjAuMjIwNSIsImF0X2hhc2giOiJrVThQTkZOUHYxS0RGUEtMT2hIY213IiwiYXV0aF90aW1lIjoxNTY3Njk5NjM5fQ.g3JD2MDGZ6wiVS9VMHpj24ER0XqJlunatmqpE7sRarMkhMHMTk7j8gty1lpqVBC6Z8L5CZuewdzLuJ5Odrd3_c1cX7gparTQE4jCyvyTACCPKHXReTC2hGRIEnAogcxv6HDWrtZgb3ENhoGhZW778d70DUdd-e4KKiAvzLOse-endHr51PaR1gv-cHPcwnm3NQZ144I-xhpU5TD9VQJ9IgLQvZGZ8fi8SOcu6rrk5ZOr0mpt0NbJNGYgH5-8iuSxo18QBWZDXoEGNsa4kS5GDkq5Cekxt7JsJFc_L1Np94giXhpbYHqhcO1pZSGFrJVaMvMMftZfuS_T3sh2yCqkcA"
}

但是,B 仍然不起作用。今天我撤销了 A 的 key 并创建了一个新的,现在它不再适用于新的,但仍然适用于旧的,即使我在 Dev Portal 上删除了它。我很困惑。

响应错误:

{
    "error": "invalid_client"
}

我想知道 Apple 是否需要一些时间索引或类似的东西。我只是想了解这是如何工作的。

最佳答案

关于如何从服务器端的 iOS 应用程序验证 Apple 登录,我一直在摸不着头脑,但找不到太多关于它的文档。

我将在此处保留我在 nodeJS 中的实现,以防它对任何人有帮助;我实际上遵循了概述的方法 here通过柯蒂斯赫伯特

  1. 从 iOS 应用程序中,您可以获得一个 ASAuthorizationAppleIDCredential,其中包括用户 (id)、电子邮件和 identityToken(短期 JWT)等详细信息
  2. 在服务器端,您可以使用 https://appleid.apple.com/auth/keys 中提供的 Apple Json Web Keys生成公钥。
    {
      "keys": [
        {
          "kty": "RSA",
          "kid": "86D88Kf",
          "use": "sig",
          "alg": "RS256",
          "n": "iGaLqP6y-SJCCBq5Hv6pGDbG_SQ11MNjH7rWHcCFYz4hGwHC4lcSurTlV8u3avoVNM8jXevG1Iu1SY11qInqUvjJur--hghr1b56OPJu6H1iKulSxGjEIyDP6c5BdE1uwprYyr4IO9th8fOwCPygjLFrh44XEGbDIFeImwvBAGOhmMB2AD1n1KviyNsH0bEB7phQtiLk-ILjv1bORSRl8AK677-1T8isGfHKXGZ_ZGtStDe7Lu0Ihp8zoUt59kx2o9uWpROkzF56ypresiIl4WprClRCjz8x6cPZXU2qNWhu71TQvUFwvIvbkE1oYaJMb0jcOTmBRZA2QuYw-zHLwQ",
          "e": "AQAB"
        },
        {
          "kty": "RSA",
          "kid": "eXaunmL",
          "use": "sig",
          "alg": "RS256",
          "n": "4dGQ7bQK8LgILOdLsYzfZjkEAoQeVC_aqyc8GC6RX7dq_KvRAQAWPvkam8VQv4GK5T4ogklEKEvj5ISBamdDNq1n52TpxQwI2EqxSk7I9fKPKhRt4F8-2yETlYvye-2s6NeWJim0KBtOVrk0gWvEDgd6WOqJl_yt5WBISvILNyVg1qAAM8JeX6dRPosahRVDjA52G2X-Tip84wqwyRpUlq2ybzcLh3zyhCitBOebiRWDQfG26EH9lTlJhll-p_Dg8vAXxJLIJ4SNLcqgFeZe4OfHLgdzMvxXZJnPp_VgmkcpUdRotazKZumj6dBPcXI_XID4Z4Z3OM1KrZPJNdUhxw",
          "e": "AQAB"
        }
      ]
    }
  1. 最后,您可以使用公钥验证 identityToken 以确保它是由 Apple 生成的。我用了图书馆 jose为它
    const axios = require('axios').default;
    const jose = require('jose')
    const {
      JWKS,  // JSON Web Key Set (JWKS)
      JWT,   // JSON Web Token (JWT)
      errors // errors utilized by jose
    } = jose    
    axios.get('https://appleid.apple.com/auth/keys')
                .then(function (response) {
                    // handle success
                    const key = jose.JWKS.asKeyStore(response.data);
                    const verified = jose.JWT.verify(identityToken, key);
                })
                .catch(function (error) {
                    // handle error
                    console.log(error);
                })
                .then(function () {
                    // always executed
                });

最后,您会得到一个结构与解码 JWT (identityToken) 相同的对象,您可以在其中验证它;

  • iss 是 https://appleid.apple.com
  • aud 是您的应用程序包 ID
  • 电子邮件和子匹配您的 ASAuthorizationAppleIDCredential 值
    {
            "iss": "https://appleid.apple.com",
            "aud": "BundleID",
            "sub": "credential.user",
            "email": "credential.email",
        }

关于ios - Sign in with Apple (iOS App + Backend verification) API 返回错误 "invalid_client",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57809927/

相关文章:

ios - 使用 Phonegap 搜索和添加 Facebook 好友

php - 创建 Google 联系人 --> 为什么只有 "NAME"没有插入新联系人?

ios - View Controller 更改时的间隙

api - Joomla 安全 REST API OAuth

node.js - 使用 OAuth 通过 REST API 从 Magento 到 NodeJS

asp.net-core - Okta 使用 OpenID Connect 配置中的公钥验证 JWT token

java - Spring security AntMatcher 不工作

java - 使用 JWT (java-jwt) 验证签名

ios - 在 Objective c 中使用 Swift 类。发生未声明的标识符错误

ios - 如何设置 UITabBarItem 选择的色调,***包括系统项目*** (iOS 7)