3 Replies
      Latest reply on Sep 11, 2019 5:15 PM by jaguth
      sudarshan.barigela Level 1 Level 1 (0 points)

        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;

          }

         

        }

        • Re: Unable to verify authorization token
          rroyo Level 1 Level 1 (0 points)

          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.

          • Re: Unable to verify authorization token
            skuehn Level 1 Level 1 (0 points)

            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();
            }