invalid_client 用于使用苹果登录

时间:2023-01-16
本文介绍了invalid_client 用于使用苹果登录的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着跟版网的小编来一起学习吧!

问题描述

我想达到的目标:

  • iOS 客户端向后端发送 JWT 令牌.
  • 后端 (Java) 调用 https://appleid.apple.com/auth/token验证令牌.

到目前为止我所拥有的:

拨打 Apple 验证电话:

 restTemplate = new RestTemplate();HttpHeaders 标头 = 新的 HttpHeaders();headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);多值映射<字符串,字符串>map = new LinkedMultiValueMap<>();map.add("client_id", clientId);//app_id 像 com.app.id字符串令牌 = generateJWT();//生成的 jwtmap.add("client_secret", token);map.add("grant_type", "authorization_code");map.add("code", authorizationCode);//我们从 iOS 获得的 JWT 代码HttpEntity<MultiValueMap<字符串,字符串>>request = new HttpEntity<>(map, headers);最终字符串 appleAuthURL = "https://appleid.apple.com/auth/token";字符串响应 = restTemplate.postForObject(appleAuthURL, request, String.class);

代币生成:

 final PrivateKey privateKey = getPrivateKey();最终 int 到期 = 1000 * 60 * 5;字符串令牌 = Jwts.builder().setHeaderParam(JwsHeader.KEY_ID, keyId)//我从 Apple 获得的密钥 id.setIssuer(teamId).setAudience("https://appleid.apple.com").setSubject(clientId)//应用 id com.app.id.setExpiration(new Date(System.currentTimeMillis() + expire)).setIssuedAt(新日期(System.currentTimeMillis())).signWith(SignatureAlgorithm.ES256, privateKey)//ECDSA 使用 P-256 和 SHA-256.袖珍的();返回令牌;

从文件中获取我的私钥:

 final Reader pemReader = new StringReader(getKeyData());最终 PEMParser pemParser = 新 PEMParser(pemReader);最终 JcaPEMKeyConverter 转换器 = 新 JcaPEMKeyConverter();最终 PrivateKeyInfo 对象 = (PrivateKeyInfo) pemParser.readObject();最终 PrivateKey pKey = converter.getPrivateKey(object);

我确认我的 JWT 具有所有必填字段:

<代码>{"kid": "与我的钥匙 ID 相同的钥匙",alg":ES256"}{"iss": "废话","aud": "https://appleid.apple.com",子":com.app.id",exp":1578513833,iat":1578513533}

解决方案

这行引起了我的注意:

map.add("code", authorizationCode);//我们从 iOS 获得的 JWT 代码

authorizationCode 不是 jwt

JSON Web Tokens 由 3 个部分组成,用点分隔

authorizationCode 有 4 个部分,如下所示:

text1.text2.0.text3

您可能正在使用 iOS 应用程序中的 identityToken 而不是 authorizationCode

这是您检索它的方式:

let authorizationCode = String(data: appleIDCredential.authorizationCode!, encoding: .utf8)!打印(授权码:(授权码)")

对于那些在遇到相同的 invalid_client 错误后可能来到这里的人来说,记住以下几点也很好:

<块引用>

  1. kid 是 developer.apple.com/account/resources/authkeys/list 中私钥的 ID

  2. keyFile 是保存从 developer.apple.com 下载的私钥的文件

  3. 登录developer.apple.com点击账号可以找到teamID,右上角可以看到teamID

  4. aud 中的值应该是https://appleid.apple.com

  5. app_id 是应用程序的包标识符

如果它可能有帮助,这里有一个在 python 中创建 client_secret 的可行解决方案:

# $ pip install pyjwt导入 jwt进口时间孩子=myKeyId"keyFile = "/pathToFile/AuthKey.p8";键="使用 open(keyFile, 'r') 作为 myFile:键 = myFile.read()打印(键)timeNow = int(round(time.time()))time3Months = timeNow + 86400*90索赔= {'iss':团队ID,'iat':时间现在,'exp': time3Months,'aud': 'https://appleid.apple.com',子":app_id,}秘密= jwt.encode(声明,密钥,算法='ES256',标题={'kid':kid})打印(秘密:")打印(秘密)client_secret = secret.decode("utf-8")打印(client_secret)

What I try to achieve:

  • iOS client sends a JWT token to the backend.
  • Backend (Java) calls https://appleid.apple.com/auth/token to verify the token.

what I have so far:

to make Apple verification call:

        restTemplate = new RestTemplate();

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
        map.add("client_id", clientId); // app_id like com.app.id
        String token = generateJWT();   // generated jwt
        map.add("client_secret", token); 
        map.add("grant_type", "authorization_code");
        map.add("code", authorizationCode);  // JWT code we got from iOS
        HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map, headers);

        final String appleAuthURL = "https://appleid.apple.com/auth/token";
        String response = restTemplate.postForObject(appleAuthURL, request, String.class);

token generation:

        final PrivateKey privateKey = getPrivateKey();
        final int expiration = 1000 * 60 * 5;

        String token = Jwts.builder()
                .setHeaderParam(JwsHeader.KEY_ID, keyId) // key id I got from Apple 
                .setIssuer(teamId)  
                .setAudience("https://appleid.apple.com")
                .setSubject(clientId) // app id com.app.id
                .setExpiration(new Date(System.currentTimeMillis() + expiration))
                .setIssuedAt(new Date(System.currentTimeMillis()))
                .signWith(SignatureAlgorithm.ES256, privateKey) // ECDSA using P-256 and SHA-256
                .compact();

        return token;

to get my private key from the file:

        final Reader pemReader = new StringReader(getKeyData());
        final PEMParser pemParser = new PEMParser(pemReader);
        final JcaPEMKeyConverter converter = new JcaPEMKeyConverter();
        final PrivateKeyInfo object = (PrivateKeyInfo) pemParser.readObject();
        final PrivateKey pKey = converter.getPrivateKey(object);

I confirmed my JWT has all required fields:

{
  "kid": "SAME KEY AS MY KEY ID",
  "alg": "ES256"
}

{
  "iss": "Blahblah",
  "aud": "https://appleid.apple.com",
  "sub": "com.app.id",
  "exp": 1578513833,
  "iat": 1578513533
}

解决方案

This line caught my attention:

map.add("code", authorizationCode);  // JWT code we got from iOS

The authorizationCode is not a jwt

JSON Web Tokens consist of 3 parts separated by dots

but the authorizationCode has 4 parts like this:

text1.text2.0.text3

You are probably using the identityToken from the iOS app instead of the authorizationCode

This is how you retrieve it:

let authorizationCode = String(data: appleIDCredential.authorizationCode!, encoding: .utf8)!
print("authorizationCode: (authorizationCode)")

Also good to have the following in mind for those who might come here after getting the same invalid_client error:

  1. kid is the id for the private key from developer.apple.com/account/resources/authkeys/list

  2. keyFile is the file holding the private key downloaded from developer.apple.com

  3. teamID can be found by logging in to developer.apple.com and clicking on account, the teamID can be seen in the upper right corner

  4. the value in aud should be https://appleid.apple.com

  5. app_id is the bundle identifier for the app

In case it might help, here is a working solution in python to create a client_secret:

# $ pip install pyjwt
import jwt
import time

kid = "myKeyId"  
keyFile = "/pathToFile/AuthKey.p8"
key = ""
with open(keyFile, 'r') as myFile:
    key = myFile.read()

print(key)

timeNow = int(round(time.time()))
time3Months = timeNow + 86400*90

claims = {
    'iss': teamID,
    'iat': timeNow,
    'exp': time3Months,
    'aud': 'https://appleid.apple.com',
    'sub': app_id,
}


secret = jwt.encode(claims, key, algorithm='ES256', headers={'kid': kid})
print("secret:")
print(secret)
client_secret = secret.decode("utf-8")
print(client_secret)

这篇关于invalid_client 用于使用苹果登录的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!

上一篇:Spring Security MultiHttpSecurity 配置使我可以执行两种类型的身份验证.JWT 令牌和会 下一篇:混合身份验证 - 基于 Spring MVC 会话 + 基于 JWT 令牌

相关文章

最新文章