Создайте и подпишите JWT в Scala для Apple AppStore Connect

#ios #scala #jwt #app-store-connect

Вопрос:

я хочу создать JWT в приложении scala для общения с API Apple AppStore Connect. я следую руководству здесь

я получаю неверную подпись на jwt.io при создании JWT с приведенным ниже кодом. запрос на подключение к appstore приводит к 401

я могу убедиться, что JWT правильно кодирует заголовок и полезную нагрузку на http://jwt.io

глядя на эту библиотеку, я думаю, что выбираю правильный алгоритм кривой:

После создания токена необходимо подписать его закрытым ключом, предоставленным Apple, с использованием алгоритма цифровой подписи с эллиптической кривой (ECDSA) с кривой P-256 и алгоритмом хэширования SHA-256, или 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. где вы получили ошибку «недопустимая подпись»? Когда вы на самом деле использовали токен или просто когда вы его проверили jwt.io?

2. да, когда я проверял jwt.io. запрос на подключение к appstore дает 401. обновит мой вопрос

3. Когда вы проверяли jwt.io, вы предоставили открытый ключ? Или токен содержит достаточно информации (URL-адрес эмитента, идентификатор ключа), чтобы jwt.io можно ли получить открытый ключ из конечной точки? Pwoplw часто думают, что подпись недействительна, но, не зная открытого ключа, jwt.io не могу проверить.

4. я вижу, что заголовок и полезная нагрузка верны без предоставления открытого ключа. похоже, я не могу ввести открытый ключ, не введя также закрытый ключ на jwt.io и я не хотел этого делать

5. выберите алгоритм в раскрывающемся списке, затем вставьте открытый ключ в поле открытый ключ в правых столбцах и, наконец, вставьте маркер, созданный с помощью кода, в поле слева. Для этого вам действительно не нужен закрытый ключ.

Ответ №1:

Я могу предложить две вещи, чтобы попробовать:

  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
  }
 

Комментарии:

1. как выглядит ваш build.sbt, чтобы получить эту зависимость?

2. я добавил "org.bouncycastle" % "bcprov-jdk15on" % "1.68" , но он не может найти PEMParser , например

3. Это тот, с которым я связался. Я использую их напрямую через библиотеку Intellij и артефакты. «org.bouncycastle» % «bcpkix-jdk15on» % «1.68» Я вижу, что это единственная зависимость, связанная с bountycastle в моем проекте

4. Это «bcpkix», а не «bcprov» .

5. ты мой спаситель, спасибо тебе! для записи решение 2 сработало для меня!