iosscalajwtjjwtdevicecheck

Generating a JWT for Apple's DeviceCheck API


I'm attempting to use the DeviceCheck API from Apple. I can't seem to craft a request that doesn't fail with a 401 Unable to verify authorization token I've tried a handful of minor variations.

import java.security.KeyFactory
import java.security.spec.PKCS8EncodedKeySpec
import java.util.Base64

import io.jsonwebtoken.{Jwts, SignatureAlgorithm}

val deviceCheckPrivateKey = "<Key in plaintext without the key-guards>"
val privateKey = KeyFactory.getInstance("EC").generatePrivate(new PKCS8EncodedKeySpec(Base64.getDecoder.decode(deviceCheckPrivateKey)))

val builder = Jwts
  .builder()
  .setHeaderParam("kid", "<key-id-from-file>")
  .signWith(SignatureAlgorithm.ES256, privateKey)
  .claim("iss", "<team-id>")
  .claim("iat", System.currentTimeMillis())

println(builder.compact())

I take the output of this scratch file and plug it in here:

curl -i -H "Authorization: Bearer <Output>" -X POST --data-binary @ValidQueryRequest.json https://api.development.devicecheck.apple.com/v1/query_two_bits 

as recommended by Apple's documentation.

Is the overall structure of this right? I'm trying to follow this tutorial which implies this structuring:

Overview of JWT signing process

But this blurb from Apple:

Each request you send to the query and update endpoints must include an authorization header that contains your authentication key. The authentication key must must use the ES256 algorithm and be in the Base 64 URL–encoded JSON web token format. If your token doesn't use this format, you receive a BAD_AUTHENTICATION_TOKEN HTTP error.

Suggests that rather than signing using the key, my request should "contain my authentication key".


Solution

  • According to: https://www.rfc-editor.org/rfc/rfc7519#section-4.1.6

    val builder = Jwts
      .builder()
      .setHeaderParam("kid", "<key-id-from-file>")
      .signWith(SignatureAlgorithm.ES256, privateKey)
      .claim("iss", "<team-id>")
      .claim("iat", System.currentTimeMillis()) // <--- Should be seconds, not milliseconds