我需要为 Store Connect API 生成 JWT 令牌。我正在尝试使用 jwt ruby gem ruby-jwt。这是我的令牌生成代码,
payload = {
'iss': my_issuer_id_from_db,
'exp': generated_unix_timestamp, #Time.now + 20min
'aud': 'hard_coded_string_from_doc'
}
header = {
'alg': 'ES256',
'kid': my_key_id_from_db,
'typ': 'JWT'
}
private_key = OpenSSL::PKey.read(File.read('/tmp/private_key.pem'))
# private_key - <OpenSSL::PKey::EC:0x000000000XXXXXXX>
@token = JWT.encode(payload, private_key, 'ES256', header)
# encoded_header.encoded_payload.emcoded_signature
我将此令牌放入请求标头中:
headers = { Authorization: 'Bearer' + @token }
我收到的回复:
"errors": [{
"status": "401",
"code": "NOT_AUTHORIZED",
"title": "Authentication credentials are missing or invalid.",
"detail": "Provide a properly configured and signed bearer token, and make sure that it has not expired. Learn more about Generating Tokens for API Requests https://developer.apple.com/go/?id=api-generating-tokens"
}]
}
我认为问题在于令牌(直接带有签名)。当我尝试使用在线工具解码令牌时,我的有效负载和标头已正确解码。状态:签名无效
我做错了什么?有什么想法如何正确地做到这一点吗?
我刚刚在这里创建了python3版本。
401 Authentication credentials are missing or invalid
可能与获得时间issued
或expired
有关。
检查您的函数获取时间是否为 Apple 建议的
UNIX epoch time
。
import jwt
import datetime as dt
key_id = '#####'
alg = 'ES256'
typ = 'JWT'
issue_id = '##########################'
aud = 'appstoreconnect-v1'
bid = '####' # Your app’s bundle ID (Ex: “com.example.testbundleid2021”)
# Define issue timestamp.
issued_at_timestamp = int(dt.datetime.now().timestamp())
# Define expiration timestamp. May not exceed 20 minutes from issue timestamp.
expiration_timestamp = issued_at_timestamp + 20*60
# Define JWT headers.
headers = dict()
headers['alg'] = alg
headers['kid'] = key_id
headers['typ'] = typ
# Define JWT payload.
payload = dict()
payload['iss'] = issue_id
payload['iat'] = issued_at_timestamp
payload['exp'] = expiration_timestamp
payload['aud'] = aud
payload['bid'] = bid
# Path to signed private key.
KEY_FILE = '#########.p8'
with open(KEY_FILE,'r') as key_file:
key = ''.join(key_file.readlines())
client_secret = jwt.encode(
payload=payload,
headers=headers,
algorithm=alg,
key=key
)
with open('client_secret.txt', 'w') as output:
output.write(client_secret)
# Usage, after run this code by python3
# get token from `client_secret.txt` and replace to [signed token]
# Remember expired time maximum is 20 minutes
#
# curl -v -H 'Authorization: Bearer [signed token]' "https://api.appstoreconnect.apple.com/v1/apps"
#
# More detail https://developer.apple.com/documentation/appstoreconnectapi/generating_tokens_for_api_requests
我遇到了类似的身份验证错误,即NOT_AUTHORIZED。我通过以下步骤解决了这个问题:
Bearer
令牌:参考:https://medium.com/xcblog/generating-jwt-tokens-for-app-store-connect-api-2b2693812a35
require "base64"
require "jwt"
ISSUER_ID = "YOUR_ISSUER_ID"
KEY_ID = "YOUR PRIVATE KEY ID" // this is ID part from downloaded .p8 file name (see below for ref.)
private_key = OpenSSL::PKey.read(File.read(path_to_your_private_key/AuthKey_#{KEY_ID}.p8)) // you can enclose your file path in quotes if needed, and can pass here totally static file path (here we are reusing Key_ID variable)
token = JWT.encode(
{
iss: ISSUER_ID,
exp: Time.now.to_i + 20 * 60,
aud: "appstoreconnect-v1"
},
private_key,
"ES256",
header_fields={
kid: KEY_ID }
)
puts token
然后在 Mac 上使用以下命令运行此脚本。
$ ruby jwt.rb
这将在您的终端屏幕上显示一个有效的
Bearer
令牌,您可以在下一步中使用。
备注:
- 为了运行上面的脚本,您需要安装
。ruby
- 您将从您的开发者帐户复制发行人 ID。如果没有,请生成一个。
- 确保您针对经过身份验证的用户使用“.p8”证书,这意味着您下载“.p8”证书的帐户应该有权执行 API 级别操作。对于我的情况,我使用Admin类型帐户。最初,我使用的是 Developer 类型的用户帐户,当我进行最后的 Curl 调用来获取令牌时,它不断地给我 Not_Authorized 错误。
现在,我们已经了解了如何生成令牌来访问 App Store Connect API,我们可以通过传递授权标头来使用它。例如,获取我们可以使用的所有用户的列表
$ curl https://api.appstoreconnect.apple.com/v1/users --Header "Authorization: Bearer lOOOOOOOOOOOONG_GENERATED_TOKEN"
这将列出 App Store Connect 的所有用户。请记住,我们必须在发出的每个请求中使用此令牌,并且必须每 20 分钟后创建新令牌。
您传入的授权字符串中缺少空格。修改为
后,您的代码工作正常headers = { Authorization: 'Bearer ' + @token }
我有一个 2023 年的答案,它在 @Nah 的答案中利用了 Ruby 脚本,但对我有用,因为它添加了旧答案中缺少的一些键。
Ruby 脚本:
require "base64"
require "jwt"
ISSUER_ID = "YOUR-ISSUER-ID"
KEY_ID = "YOUR-KEY-ID"
private_key = OpenSSL::PKey.read(File.read("PATH_TO_KEY_DOWNLOADED_FROM_APP_STORE_CONNECT.p8"))
token = JWT.encode(
{
iss: ISSUER_ID,
exp: Time.now.to_i + 20 * 60,
aud: "appstoreconnect-v1",
bid: "YOUR_BUNDLE_ID"
},
private_key,
"ES256",
header_fields = {
alg: "ES256",
kid: KEY_ID,
typ: "JWT"
}
)
puts token
然后,您可以在与 Apple 通信时获取该密钥并将其放入
Authorization
标头中。
例如,我需要从 Apple 获取应用内购买事件的测试通知,因此我可以将令牌放入curl 请求中并获得 200:
curl -v --request POST \
-H "Authorization: Bearer YOUR_LONG_TOKEN_HERE" \
"https://api.storekit-sandbox.itunes.apple.com/inApps/v1/notifications/test"
如果您更喜欢使用 Postman,请在
Authorization
选项卡中,将 Bearer Token
设置为 Ruby 脚本生成的令牌。