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?