在 Scala 中为 Apple AppStore Connect 创建并签署 JWT

Create and sign JWT in Scala for Apple AppStore Connect

我想在 scala 应用程序中创建一个 JWT 来与 Apple 的 AppStore Connect api. i'm following the guide here

我在使用以下代码创建 JWT 时在 jwt.io 上收到无效签名。对应用商店连接的请求导致 401

我可以验证 JWT 是否在 http://jwt.io

上正确编码 header 和有效负载

查看 this 库,我想我正在选择正确的曲线算法:

After creating the token, one must sign it with an Apple-provided private key, using the Elliptic Curve Digital Signature Algorithm (ECDSA) with the P-256 curve and the SHA-256 hash algorithm, or ES256.

我不确定哪里出了问题 - 也许我没有正确生成 S 值?

  def generateJWT(): String = {
    val privateKeyBytes: Array[Byte] =
      Base64.getDecoder.decode("base64 representation of private key")
    val S = BigInt(privateKeyBytes)
    
    val curveParams = ECNamedCurveTable.getParameterSpec("P-256")
    val curveSpec: ECParameterSpec =
      new ECNamedCurveSpec("P-256", curveParams.getCurve(), curveParams.getG(), curveParams.getN(), curveParams.getH());
    val privateSpec = new ECPrivateKeySpec(S.underlying, curveSpec)

    val privateKey =
      KeyFactory.getInstance("EC").generatePrivate(privateSpec)

    val unixTimestamp: Long = Instant.now.getEpochSecond
    val fiveMins = unixTimestamp.toInt + 300

    val header = Map[String, Object](
      "kid" -> "appstore connect Key Identifier",
      "typ" -> "JWT",
      "alg" -> "ES256"
    )

    val payload = Map[String, Object](
      "iss" -> "issuer ID from the API Keys page in App Store Connect",
      "aud" -> "appstoreconnect-v1",
      "exp" -> new Integer(fiveMins)
    )

    Jwts
      .builder()
      .setHeaderParams(header.asJava)
      .setClaims(payload.asJava)
      .signWith(SignatureAlgorithm.ES256, privateKey)
      .compact()
  }

我可以建议尝试两件事:

  1. JwtBuilder signWith(SignatureAlgorithm var1, Key var2) 已弃用。您可以尝试使用 JwtBuilder signWith(Key var1, SignatureAlgorithm var2) ,看看是否成功吗?
  2. 如果没有,您可以尝试使用 bountycastle ,它对我有用。以下是获取私钥的代码片段。
  def getPrivateKey(): PrivateKey = {

    val pemParser = new PEMParser(new FileReader(<Your Apple-AuthKey file with extension .p8>))
    val converter = new JcaPEMKeyConverter
    val privateKeyInfo = pemParser.readObject.asInstanceOf[PrivateKeyInfo]
    val pKey = converter.getPrivateKey(privateKeyInfo)
    pemParser.close()
    pKey
  }