Unable to verify authorization token

We're trying to generate and validate the authorization token for device check api , but getting the following error. Please check and update us with a solution.


Error : "Unable to verify authorization token"

Status Code : 401


We've written the following code . Please verify and update if any changes need to be made.



import java.io.BufferedReader;

import java.io.File;

import java.io.FileReader;

import java.io.IOException;

import java.security.KeyFactory;

import java.security.NoSuchAlgorithmException;

import java.security.PrivateKey;

import java.security.spec.InvalidKeySpecException;

import java.security.spec.PKCS8EncodedKeySpec;

import java.util.Date;


import org.bouncycastle.asn1.cms.TimeStampAndCRL;


import com.nimbusds.jose.JWSAlgorithm;

import com.nimbusds.jose.JWSHeader;

import com.nimbusds.jose.JWSSigner;

import com.nimbusds.jose.crypto.ECDSASigner;

import com.nimbusds.jwt.JWTClaimsSet;

import com.nimbusds.jwt.SignedJWT;

import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;


public class JWTUtil {



public static void main(String[] args) {

generateJWTForiOS();

}


public static void generateJWTForiOS() {

try {

String kid = "-------"; // Can be found at: https://developer.apple.com/account/ios/authkey/

String teamId = "-------"; // Can be found at: https://developer.apple.com/account/#/membership/

PrivateKey key = loadIOSPrivateKey();

Long timestamp = new Date().getTime();

JWTClaimsSet claimsSet = new JWTClaimsSet.Builder().build();

JWSHeader header = new JWSHeader.Builder(JWSAlgorithm.ES256).keyID(kid).customParam("iat", timestamp).customParam("iss", teamId).build();

SignedJWT signedJWT = new SignedJWT(header, claimsSet);

JWSSigner signer = new ECDSASigner((java.security.interfaces.ECPrivateKey) key);

signedJWT.sign(signer);

String token = signedJWT.serialize();

System.out.println(token);

} catch (Exception e) {

e.printStackTrace();

}

}


public static PrivateKey loadIOSPrivateKey() {


PrivateKey privateKey = null;


try {


File file = new File("..\\AuthKey_XXXXXXXX.p8");


BufferedReader br = new BufferedReader(new FileReader(file));


String st;

StringBuilder strBuilder = new StringBuilder();

while ((st = br.readLine()) != null){

strBuilder.append(st);

}


String privateKeyPEM = strBuilder.toString();

privateKeyPEM = privateKeyPEM.replace("-----BEGIN PRIVATE KEY-----", "")

.replace("-----END PRIVATE KEY-----", "").replaceAll("\\s", "");


byte[] keyBytes = java.util.Base64.getDecoder().decode(privateKeyPEM);

KeyFactory keyFactory = KeyFactory.getInstance("EC");

privateKey = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(keyBytes));


} catch (IOException | NoSuchAlgorithmException | InvalidKeySpecException e) {

System.out.println(e);

}


return privateKey;

}


}

Replies

Hello,


Did you figure out how to create the JWT token to send to apple api? If so, can you please post a working sample code? I'm also facing the same issue, while implementing the device check api.

Use seconds instead of java Date milliseconds or use Date objects directly. And write complete JWSHeader and JWTClaimSet.


String inputKeyFile = readAppleKeyFile();
inputKeyFile = inputKeyFile.replaceFirst("-----BEGIN PRIVATE KEY-----", "");
inputKeyFile = inputKeyFile.replaceFirst("-----END PRIVATE KEY-----", "");
inputKeyFile = inputKeyFile.replaceAll("\\s", "");


String clientSecret = "";
try {
  final byte[] keyBytes = java.util.Base64.getDecoder().decode(inputKeyFile);
  final KeyFactory keyFactory = KeyFactory.getInstance("EC");
  final PrivateKey privateKey = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(keyBytes));

  final Date timestamp = new Date();
  final Date exp = new Date(timestamp.getTime() + ttlMs);


  // see https://developer.apple.com/documentation/signinwithapplerestapi/generate_and_validate_tokens
  final JWSHeader header = new JWSHeader.Builder(JWSAlgorithm.ES256)
  .keyID(keyId)
  .build();

  final JWTClaimsSet claimsSet = new JWTClaimsSet.Builder()
  .issuer(teamId)
  .issueTime(timestamp)
  .expirationTime(exp)
  .audience(audience)
  .subject(clientId)
  .build();

  SignedJWT signedJWT = new SignedJWT(header, claimsSet);
  JWSSigner signer = new ECDSASigner((java.security.interfaces.ECPrivateKey) privateKey);
  signedJWT.sign(signer);
  String token = signedJWT.serialize();

  System.out.println(token);
  clientSecret = token;
} catch (Exception e) {
  e.printStackTrace();
}

Thank you skuehn, that really helped me!