首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >使用Apple登录(iOS App +后端验证) API返回错误"invalid_client“

使用Apple登录(iOS App +后端验证) API返回错误"invalid_client“
EN

Stack Overflow用户
提问于 2019-09-05 16:52:30
回答 6查看 15K关注 0票数 19

我正在尝试用一个应用程序和一个后端实现与苹果登录的iOS。目标是:

  1. 用户在iOS应用程序上注册
  2. 在得到肯定的响应后,应用程序调用后端的端点并提交authorizationCode
  3. 后端现在需要通过另一个对苹果服务器的调用来验证authorizationCode

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

URL

代码语言:javascript
运行
复制
https://appleid.apple.com/auth/token

查询参数

代码语言:javascript
运行
复制
client_id     = com.mycompany.appname
client_secret = ...
code          = ... // `authorizationCode` from the signin in the iOS app
grant_type    = authorization_code

我为JWT生成了一个client_secret

JWT特性

代码语言:javascript
运行
复制
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)创建了两个键,用它生成秘密,今天应用程序A成功了,我得到了积极的响应:

阳性反应

代码语言:javascript
运行
复制
{
    "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的密钥,创建了一个新的密钥,现在它不再适用于新的密钥,但对旧的密钥仍然有效,尽管我在Dev Portal上删除了它。我真的很困惑。

响应误差

代码语言:javascript
运行
复制
{
    "error": "invalid_client"
}

我想知道苹果是否需要一些时间索引之类的东西。我只想知道这是怎么回事。

EN

回答 6

Stack Overflow用户

发布于 2020-05-21 08:53:58

在如何验证服务器端的iOS应用程序与苹果的登录时,我绞尽脑汁,却找不到太多的文档。

我将把我在nodeJS中的实现留在这里,以防它对任何人有帮助;我实际上遵循了柯蒂斯赫伯特( Curtis Herbert )概述的这里方法。

  1. 从iOS应用程序中,您可以得到一个ASAuthorizationAppleIDCredential,其中包括一个用户(id)、一个电子邮件和一个identityToken (短暂的JWT)。
  2. 在服务器端,您可以使用https://appleid.apple.com/auth/keys中可用的Apple来生成公钥。
代码语言:javascript
运行
复制
    {
      "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,以确保它是由苹果生成的。我用图书馆的荷西做的
代码语言:javascript
运行
复制
    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值匹配
代码语言:javascript
运行
复制
    {
            "iss": "https://appleid.apple.com",
            "aud": "BundleID",
            "sub": "credential.user",
            "email": "credential.email",
        }
票数 10
EN

Stack Overflow用户

发布于 2019-12-09 04:44:03

发生这种情况的原因有几个:

  1. client_id for web应该是服务id。对于应用程序,它应该是apps id。(即使使用本机apple对话框,获取code,然后将其传递给get服务器,然后使用它请求令牌API。) JWT调用中的sub应该与client_id相同。见答案苹果论坛
  2. 您的JWT库不支持Apple登录所需的加密。为此,他们使用JWT标准,使用带有P-256曲线和SHA256散列的椭圆曲线算法。换句话说,他们使用ES256 JWT算法。一些JWT库不支持椭圆曲线方法,所以在开始尝试之前请确保您的库支持椭圆曲线方法。客户端
  3. 象征性的日期。尝试设置以下内容

到期时间: DateTime.UtcNow.AddDays(2),//到期时间最长为6个月issuedAt: DateTime.UtcNow.AddDays(-1),notBefore: DateTime.UtcNow.AddDays(-1),

它在我的when服务器上的invalid_client失败了,因为苹果认为它是来自未来的证书,当我有:

代码语言:javascript
运行
复制
 expires: DateTime.UtcNow.AddMinutes(5), // expiry can be a maximum of 6 months
 issuedAt: DateTime.UtcNow,
 notBefore: DateTime.UtcNow,
  1. 在调用令牌API时,指定用户代理头也很重要。还值得一提的是,curl可以抛出此错误,而当您从web服务器调用它时,它将正常工作。
  2. 确保您设置的是正确的Content-Type: application/x-www-form-urlencoded头,而不是默认设置的某些库(如axios )所设置的Content-Type: application/json
票数 9
EN

Stack Overflow用户

发布于 2019-09-10 14:32:57

本地应用程序ID是以团队ID为前缀的包ID,由一个点分隔。

“Apple是一个由两个部分组成的字符串,用于标识一个或多个应用程序。具体来说,Apple是您的团队ID,而绑定ID是一个句号,用于示例:1A234H7ABC.com.yourdomain.YourApp。”

不过,我也有同样的问题让这件事起作用。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57809927

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档