Search code examples
javagoogle-cloud-platformjwtrsagoogle-cloud-iam

How to read Private Key for signing JWT header for Google OAuth2?


I am trying to get a bearer token using oAuth2 for connecting to a service account on GCP, I am following this documentation. To sign the JWT, the docs tell me to use "the private key obtained from the Google API Console".

Sign the UTF-8 representation of the input using SHA256withRSA (also known as RSASSA-PKCS1-V1_5-SIGN with the SHA-256 hash function) with the private key obtained from the Google API Console.

I have the below code in Java to read that private key from a file

File privKeyFile = new File(keyPath);
BufferedInputStream bis = new BufferedInputStream(new FileInputStream('myprivatekey.pem'));
byte[] privKeyBytes = new byte[8192]
bis.read(privKeyBytes);
bis.close();

KeyFactory keyFactory = KeyFactory.getInstance("RSA");
KeySpec ks = new PKCS8EncodedKeySpec(privKeyBytes); 

RSAPrivateKey privateKey = (RSAPrivateKey) keyFactory.generatePrivate(ks);

But this code is currently giving this exception

java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: 
invalid key format at java_security_KeyFactory$generatePrivate$0.call(Unknown Source)

I tried converting private Key to PKCS#8 format as per this post but when I run this command

openssl pkcs8 -topk8 -inform PEM -outform DER -in myprivatekey.pem  -nocrypt > pkcs8_key

I get this error

unable to load key
140735932699592:error:0906D06C:PEM routines:PEM_read_bio:no start line:/BuildRoot/Library/Caches/com.apple.xbs/Sources/libressl/libressl-22.50.3/libressl/crypto/pem/pem_lib.c:704:Expecting: ANY PRIVATE KEY

Was that not a valid RSA key which Google console provided? How can I read that key into my code so I can use it to sign the JWT?


Solution

  • The service account private key is PEM encoded RSA PKCS #8. The PKCS8EncodedKeySpec wants ASN.1 encoding without newlines, header, and tail.

    The private key in your post appears valid and in the correct format.

    WARNING: if that private key is from Google Cloud, immediately delete the key.

    Use code similar to this:

    public RSAPrivateKey readPrivateKey(File file) throws Exception {
        String key = new String(Files.readAllBytes(file.toPath()), Charset.defaultCharset());
    
        String privateKeyPEM = key
          .replace("-----BEGIN PRIVATE KEY-----", "")
          .replaceAll(System.lineSeparator(), "")
          .replace("-----END PRIVATE KEY-----", "");
    
        byte[] encoded = Base64.decodeBase64(privateKeyPEM);
    
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encoded);
        return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
    }