Skip to content

Commit da1635e

Browse files
committed
Decode OpenID token with correct public key
1 parent 68eaff7 commit da1635e

File tree

4 files changed

+40
-15
lines changed

4 files changed

+40
-15
lines changed

src/GooglePublicKey.php

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,23 +20,31 @@ public function __construct(Client $guzzle)
2020
$this->guzzle = $guzzle;
2121
}
2222

23-
public function get()
23+
public function get($kid = null)
2424
{
25-
return Cache::rememberForever(self::CACHE_KEY, function () {
26-
return $this->fetch();
27-
});
25+
$v3Certs = Cache::rememberForever(
26+
self::CACHE_KEY,
27+
function () {
28+
return $this->getv3Certs();
29+
}
30+
);
31+
32+
$cert = $kid ? collect($v3Certs)->firstWhere('kid', '=', $kid) : $v3Certs[0];
33+
34+
return $this->extractPublicKeyFromCertificate($cert);
2835
}
2936

30-
private function fetch()
37+
private function getv3Certs()
3138
{
3239
$jwksUri = $this->getJwksUri();
3340

34-
$keys = $this->getCertificateKeys($jwksUri);
35-
36-
$firstKey = $keys[1];
41+
return $this->getCertificateKeys($jwksUri);
42+
}
3743

38-
$modulus = $firstKey['n'];
39-
$exponent = $firstKey['e'];
44+
private function extractPublicKeyFromCertificate($certificate)
45+
{
46+
$modulus = $certificate['n'];
47+
$exponent = $certificate['e'];
4048

4149
$rsa = app(RSA::class);
4250

@@ -72,6 +80,15 @@ private function getCertificateKeys($jwksUri)
7280
return Arr::get($certificates, 'keys');
7381
}
7482

83+
public function getKid($openIdToken)
84+
{
85+
$response = $this->guzzle->get('https://www.googleapis.com/oauth2/v3/tokeninfo?id_token=' . $openIdToken);
86+
87+
$tokenInfo = json_decode($response->getBody(), true);
88+
89+
return Arr::get($tokenInfo, 'kid');
90+
}
91+
7592
public function isCached()
7693
{
7794
return Cache::has(self::CACHE_KEY);

src/TaskHandler.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ public function authorizeRequest()
4646
}
4747

4848
$openIdToken = $this->request->bearerToken();
49-
$publicKey = $this->publicKey->get();
49+
$kid = $this->publicKey->getKid($openIdToken);
50+
$publicKey = $this->publicKey->get($kid);
5051

5152
$decodedToken = $this->jwt->decode($openIdToken, $publicKey, ['RS256']);
5253

tests/GooglePublicKeyTest.php

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace Tests;
44

5+
use GuzzleHttp\Client;
56
use Illuminate\Support\Facades\Cache;
67
use Mockery;
78
use phpseclib\Crypt\RSA;
@@ -14,11 +15,18 @@ class GooglePublicKeyTest extends TestCase
1415
*/
1516
private $publicKey;
1617

18+
/**
19+
* @var Client
20+
*/
21+
private $guzzle;
22+
1723
protected function setUp(): void
1824
{
1925
parent::setUp();
2026

21-
$this->publicKey = app(GooglePublicKey::class);
27+
$this->guzzle = Mockery::mock(new Client());
28+
29+
$this->publicKey = new GooglePublicKey($this->guzzle);
2230
}
2331

2432
/** @test */
@@ -40,12 +48,10 @@ public function it_caches_the_gcloud_public_key()
4048
/** @test */
4149
public function it_will_return_the_cached_gcloud_public_key()
4250
{
43-
$this->app->instance(RSA::class, ($rsa = Mockery::mock(new RSA())->byDefault()));
44-
4551
$this->publicKey->get();
4652

4753
$this->publicKey->get();
4854

49-
$rsa->shouldHaveReceived('loadKey')->once();
55+
$this->guzzle->shouldHaveReceived('get')->twice();
5056
}
5157
}

tests/TaskHandlerTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ protected function setUp(): void
4242
// Ensure we don't fetch the Google public key each test...
4343
$googlePublicKey = Mockery::mock(app(GooglePublicKey::class));
4444
$googlePublicKey->shouldReceive('get')->andReturnNull();
45+
$googlePublicKey->shouldReceive('getKid')->andReturnNull();
4546

4647
$this->handler = new TaskHandler(
4748
new CloudTasksClient([

0 commit comments

Comments
 (0)