質問

I'm trying to implement a federated login system with Google and OpenID Connect, and I'm stuck verifying and parsing the JWT id token I get back from Google. I'm following Google's documentation here.

Taking the advise of the docs, I'm trying to use an existing JWT library. The most popular PHP version on GitHub seems to be PHP_JWT. The problem appears to be in the format of the JWK keys.

Google's docs, linked above, say to get the keys from the jwks_uri endpoint as shown in their discovery doc. That endpoint returns the following:

{
 "keys": [
  {
   "kty": "RSA",
   "alg": "RS256",
   "use": "sig",
   "kid": "1771931eb0eb64eb97733e857685be153e079bb9",
   "n": "AMNFQMNJw/EVwrYsyPTnEHWkaPinPb4ngc/SqD701aisFhbU9/wWoKADeFtwfBcWl1qjzIqhPorQElB+2mtiqUh3Qtaazt1x5wA9XnJDe6kjtMGm9nNLMilSVNBilAE8GIdbciMycISfOfL0WRaJrqpNxewNEVZjuYiGzOWahiDP",
   "e": "AQAB"
  },
  {
   "kty": "RSA",
   "alg": "RS256",
   "use": "sig",
   "kid": "7b3bc600209875d3c42ae277a0d018d1d21986ec",
   "n": "AN2UvG5+hNEMIPIbnpPm+JQi6LFWXBPzg3Ltb3xkVmSTjVaCFWppw/ZYRBgpToGKZP9XJstlOE88SDUFSMZIkIqtLpnUqmZax2Zc2gjEB9PhmHSH3/tTmtZ1U0X6V+crqitZ2uc3NV78vCn9/s+WuPwk/gfKBG8Cirb0fgLmsPd9",
   "e": "AQAB"
  }
 ]
}

Looking at the source for the JWT class's decode and verify methods, it seems like the $keys parameter can be an array, but they expect the array keys to be the kid and the array values to be: @param string|resource $key for HS*, a string key works. for RS*, must be a resource of an openssl public key. It's simple enough to pull out the kid properties and use them as array keys, but what should be used as the array values?

From Google's JWKs document, it looks like we're using RS*, but I have no idea what part of the key object is the resource of an openssl public key. I've tried using the entire stdClass object and just the n string, but both fail at the openssl_verify step. That function emits a notice saying: "Warning: openssl_verify(): supplied key param cannot be coerced into a public key".

So, obviously, I'm passing in the wrong key, but what is the right key?

Google's library for this seems to use a different endpoint to get the keys. That endpoint seems to return an array of certs. Do I need to use something like that instead? If so, why would the docs tell you to use the jwks_uri endpoint?

役に立ちましたか?

解決

Both endpoints contain the same informations but in different format.

The jwks_uri endpoint give you the modulus and exponent value of the RSA public key. You can use these two values to generate the PEM file you get at https://www.googleapis.com/oauth2/v1/certs.

他のヒント

For the people trying to do this in the future I'd like to provide a full answer;

The n and e parts in the jwks_uri JSON keys give the modulus and the exponent, which can be used to retrieve the public key (which is all that is required to verify the signature). How this is done in pure PHP is detailed in this post:

openssl: how can i get public key from modulus

However, you should be aware that the JSON document provided at Google's jwks_uri uses URL safe base64 encoding (i.e. normal base64 with the + and / characters replaced). Failing to take this into account might still give you an invalid certificate. Since you mention using php-jwt, working code to get the public key from the modulus and the exponent using phpseclib is:

$modulus = 'someencodedmodulusvalue';
$exponent = 'someencodedexponentvalue'; 
$rsa = new Crypt_RSA();

$modulus = new Math_BigInteger(JWT::urlsafeB64Decode($modulus), 256);
$exponent = new Math_BigInteger(JWT::urlsafeB64Decode($exponent), 256);

$rsa->loadKey(array('n' => $modulus, 'e' => $exponent));
$rsa->setPublicKey();
$pubKey = $rsa->getPublicKey();
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top