137 lines
4.0 KiB
PHP
137 lines
4.0 KiB
PHP
<?php
|
|
|
|
/*
|
|
* Copyright 2008 Google Inc.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
namespace Google\AccessToken;
|
|
|
|
use DomainException;
|
|
use Exception;
|
|
use Firebase\JWT\CachedKeySet;
|
|
use Firebase\JWT\ExpiredException;
|
|
use Firebase\JWT\JWT;
|
|
use Firebase\JWT\SignatureInvalidException;
|
|
use Google\Auth\Cache\MemoryCacheItemPool;
|
|
use GuzzleHttp\Client;
|
|
use GuzzleHttp\ClientInterface as GuzzleClientInterface;
|
|
use GuzzleHttp\Psr7\HttpFactory;
|
|
use InvalidArgumentException;
|
|
use LogicException;
|
|
use Psr\Cache\CacheItemPoolInterface;
|
|
use Psr\Http\Client\ClientInterface;
|
|
|
|
/**
|
|
* Wrapper around Google Access Tokens which provides convenience functions
|
|
*
|
|
*/
|
|
class Verify
|
|
{
|
|
const FEDERATED_SIGNON_CERT_URL = 'https://www.googleapis.com/oauth2/v3/certs';
|
|
const OAUTH2_ISSUER = 'accounts.google.com';
|
|
const OAUTH2_ISSUER_HTTPS = 'https://accounts.google.com';
|
|
|
|
/**
|
|
* @var \Firebase\JWT\JWT
|
|
*/
|
|
public JWT $jwt;
|
|
|
|
/**
|
|
* @var \Firebase\JWT\CachedKeySet
|
|
*/
|
|
private CachedKeySet $keySet;
|
|
|
|
/**
|
|
* Instantiates the class, but does not initiate the login flow, leaving it
|
|
* to the discretion of the caller.
|
|
*/
|
|
public function __construct(
|
|
?GuzzleClientInterface $http = null,
|
|
?CacheItemPoolInterface $cache = null,
|
|
?JWT $jwt = null
|
|
) {
|
|
if (null === $http) {
|
|
$http = new Client();
|
|
}
|
|
|
|
if (null === $cache) {
|
|
$cache = new MemoryCacheItemPool();
|
|
}
|
|
|
|
if (!$http instanceof ClientInterface) {
|
|
throw new InvalidArgumentException('http client must implement ' . ClientInterface::class);
|
|
}
|
|
|
|
$this->jwt = $jwt ?: $this->getJwtService();
|
|
$this->keySet = new CachedKeySet(
|
|
self::FEDERATED_SIGNON_CERT_URL,
|
|
$http,
|
|
new HttpFactory(),
|
|
$cache
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Verifies an id token and returns the authenticated apiLoginTicket.
|
|
* Throws an exception if the id token is not valid.
|
|
* The audience parameter can be used to control which id tokens are
|
|
* accepted. By default, the id token must have been issued to this OAuth2 client.
|
|
*
|
|
* @param string $idToken the ID token in JWT format
|
|
* @param string $audience Optional. The audience to verify against JWt "aud"
|
|
* @return array|false the token payload, if successful
|
|
*/
|
|
public function verifyIdToken($idToken, $audience = null)
|
|
{
|
|
if (empty($idToken)) {
|
|
throw new LogicException('id_token cannot be null');
|
|
}
|
|
|
|
// Check signature
|
|
try {
|
|
$payload = ($this->jwt)->decode($idToken, $this->keySet);
|
|
} catch (ExpiredException | SignatureInvalidException | DomainException) {
|
|
return false;
|
|
}
|
|
|
|
if (property_exists($payload, 'aud')) {
|
|
if ($audience && $payload->aud != $audience) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// support HTTP and HTTPS issuers
|
|
// @see https://developers.google.com/identity/sign-in/web/backend-auth
|
|
$issuers = [self::OAUTH2_ISSUER, self::OAUTH2_ISSUER_HTTPS];
|
|
if (!isset($payload->iss) || !in_array($payload->iss, $issuers)) {
|
|
return false;
|
|
}
|
|
|
|
return (array) $payload;
|
|
}
|
|
|
|
private function getJwtService()
|
|
{
|
|
$jwt = new JWT();
|
|
if ($jwt::$leeway < 1) {
|
|
// Ensures JWT leeway is at least 1
|
|
// @see https://github.com/google/google-api-php-client/issues/827
|
|
$jwt::$leeway = 1;
|
|
}
|
|
|
|
return $jwt;
|
|
}
|
|
}
|