You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS DeviceCheck API持续返回400:授权令牌缺失或格式错误

iOS DeviceCheck API 400错误:授权令牌缺失或格式错误

调用iOS DeviceCheck API时持续收到400错误,提示「Missing or badly formatted authorization token」(授权令牌缺失或格式错误),无论从本地服务器还是直接从App调用都存在该问题。

请求示例

curl --location 'https://api.development.devicecheck.apple.com/v1/query_two_bits' \
--header 'Authorization: Bearer <<JWT-token>>' \
--header 'Content-Type: application/json' \
--data '{
    "device_token": Token_fetched_from_Device_Check,
    "transaction_id":"c6bdb659-0ee6-443d-88cb-a8f036dfc551", 
    "timestamp": 1721300244267
}'

参数说明

  • device_token:通过DeviceCheck框架生成
  • JWT-token:使用Apple开发者门户生成的.p8文件密钥、对应keyId及团队ID(个人开发者账号)生成

已尝试的排查步骤

  • 创建.p8密钥时已启用Device Check选项
  • 等待密钥激活超过7小时后再调用API
  • 使用DeviceCheck框架生成的全新device_token进行测试

DeviceCheck令牌生成代码

if curDevice.isSupported{
     DCDevice.current.generateToken { (data, error) in
           if let data = data {
           }
     }
 }

初始JWT令牌生成代码

func createJWTToken(privateKey: String, keyID: String, teamID: String) -> String? {
        // Set up the JWT header
        var jwtHeader = Header()
        jwtHeader.kid = keyID
        
        // Set up the JWT claims
        let jwtClaims = MyClaims(iss: teamID, iat: Date())
        
        // Create the JWT
        var jwt = JWT(header: jwtHeader, claims: jwtClaims)
        
        // Convert the private key to Data
        guard let privateKeyData = Data(base64Encoded: privateKey) else {
            print("Invalid private key")
            return nil
        }
        
        
        // Sign the JWT
        let jwtSigner = JWTSigner.es256(privateKey: privateKeyData)
        
        do {
            let signedJWT = try jwt.sign(using: jwtSigner)
            return signedJWT
        } catch {
            print("Failed to sign JWT: \(error)")
            return nil
        }
    }

问题仍未解决,恳请提供技术建议。


更新:检查多语言JWT生成代码是否存在问题

Python方法

import jwt
import time
import uuid


def generate_jwt(private_key, key_id, team_id):
    headers = {
        "alg": "ES256",
        "kid": key_id,
    }
    payload = {
        "iss": team_id,
        "iat": int(time.time()),
        "exp": int(time.time()) + 3600,  # Token valid for 1 hour
    }
    token = jwt.encode(payload, private_key, algorithm="ES256", headers=headers)
    return token

# Load your private key
with open('AuthKey_abc.p8', 'r') as key_file:
    private_key = key_file.read()


key_id = "########"  # Replace with your Key ID
team_id = "#########"  # Replace with your Team ID

jwt_token = generate_jwt(private_key, key_id, team_id).decode('utf-8')
transaction_id = str(uuid.uuid4())
timestamp = int(time.time() * 1000)

print("JWT Token:", jwt_token)
print("Transaction ID:", transaction_id)
print("Timestamp:", timestamp)

Swift代码

import SwiftJWT

func createJWTToken(privateKey: String, keyID: String, teamID: String) -> String? {
        // Set up the JWT header
        var jwtHeader = Header()
        jwtHeader.kid = keyID
        
        // Set up the JWT claims
        let jwtClaims = MyClaims(iss: teamID, iat: Date())
        
        // Create the JWT
        var jwt = JWT(header: jwtHeader, claims: jwtClaims)
        
        // Convert the private key to Data
        guard let privateKeyData = Data(base64Encoded: privateKey) else {
            print("Invalid private key")
            return nil
        }
        
        // Sign the JWT
        let jwtSigner = JWTSigner.es256(privateKey: privateKeyData)
        
        do {
            let signedJWT = try jwt.sign(using: jwtSigner)
            return signedJWT
        } catch {
            print("Failed to sign JWT: \(error)")
            return nil
        }
    }


    func readFileFromBundle(fileName: String, fileType: String) -> String? {
        if let fileURL = Bundle.main.url(forResource: fileName, withExtension: fileType) {
            do {
                // Read the file contents
                let privateKey = try String(contentsOf: fileURL, encoding: .utf8)
                
                // Clean the private key by removing header, footer, and whitespace/newlines
                let cleanedKey = privateKey
                    .replacingOccurrences(of: "-----BEGIN PRIVATE KEY-----", with: "")
                    .replacingOccurrences(of: "-----END PRIVATE KEY-----", with: "")
                    .replacingOccurrences(of: "\n", with: "")
                    .replacingOccurrences(of: "\r", with: "")
                    .trimmingCharacters(in: .whitespacesAndNewlines)
                
                return cleanedKey
            } catch {
                print("Error reading private key: \(error)")
                return nil
            }
        } else {
            print("Private key file not found")
            return nil
        }
    }

Node.js代码

const privateKey = fs.readFileSync('AuthKey_abc.p8', 'utf8');

const payload = {
    iss: teamId,
    iat: curTime,
    exp: curTime + 3600 // 1 hour expiration
};

// Prepare the JWT headers
const headers = {
    kid: keyId,
    alg: 'ES256'
};

// Create and sign the JWT
var jwToken = jwt.sign(payload, privateKey, { 
    header: headers
});
console.log(jwToken)

内容的提问来源于stack exchange,提问作者Suryakant Sharma

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 15:29:52