Passed
Push — master ( 13425d...f357db )
by Alexander
02:26
created

OpenIdConnect::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 14
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 4
nc 1
nop 8
dl 0
loc 14
ccs 0
cts 5
cp 0
crap 2
rs 10
c 0
b 0
f 0

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Yii\AuthClient\Client;
6
7
use Exception;
8
use HttpException;
9
use Jose\Component\Checker\AlgorithmChecker;
0 ignored issues
show
Bug introduced by
The type Jose\Component\Checker\AlgorithmChecker was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
10
use Jose\Component\Checker\HeaderCheckerManager;
0 ignored issues
show
Bug introduced by
The type Jose\Component\Checker\HeaderCheckerManager was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
11
use Jose\Component\Core\AlgorithmManager;
0 ignored issues
show
Bug introduced by
The type Jose\Component\Core\AlgorithmManager was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
12
use Jose\Component\Core\JWKSet;
0 ignored issues
show
Bug introduced by
The type Jose\Component\Core\JWKSet was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
13
use Jose\Component\KeyManagement\JWKFactory;
0 ignored issues
show
Bug introduced by
The type Jose\Component\KeyManagement\JWKFactory was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
14
use Jose\Component\Signature\JWSLoader;
0 ignored issues
show
Bug introduced by
The type Jose\Component\Signature\JWSLoader was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
15
use Jose\Component\Signature\JWSTokenSupport;
0 ignored issues
show
Bug introduced by
The type Jose\Component\Signature\JWSTokenSupport was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
16
use Jose\Component\Signature\JWSVerifier;
0 ignored issues
show
Bug introduced by
The type Jose\Component\Signature\JWSVerifier was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
17
use Jose\Component\Signature\Serializer\CompactSerializer;
0 ignored issues
show
Bug introduced by
The type Jose\Component\Signature...lizer\CompactSerializer was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
18
use Jose\Component\Signature\Serializer\JWSSerializerManager;
0 ignored issues
show
Bug introduced by
The type Jose\Component\Signature...er\JWSSerializerManager was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
19
use Psr\Http\Client\ClientInterface;
20
use Psr\Http\Message\RequestFactoryInterface;
21
use Psr\Http\Message\RequestInterface;
22
use Psr\Http\Message\ServerRequestInterface;
23
use Psr\SimpleCache\CacheInterface;
24
use Psr\SimpleCache\InvalidArgumentException;
25
use Yiisoft\Factory\FactoryInterface;
26
use Yiisoft\Json\Json;
27
use Yiisoft\Security\Random;
0 ignored issues
show
Bug introduced by
The type Yiisoft\Security\Random was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
28
use Yiisoft\Session\SessionInterface;
29
use Yiisoft\Yii\AuthClient\Exception\InvalidConfigException;
30
use Yiisoft\Yii\AuthClient\OAuth2;
31
use Yiisoft\Yii\AuthClient\OAuthToken;
32
use Yiisoft\Yii\AuthClient\Signature\HmacSha;
33
use Yiisoft\Yii\AuthClient\StateStorage\StateStorageInterface;
34
35
use function in_array;
36
37
/**
38
 * OpenIdConnect serves as a client for the OpenIdConnect flow.
39
 *
40
 * This class requires `web-token/jwt-checker`,`web-token/jwt-key-mgmt`, `web-token/jwt-signature`, `web-token/jwt-signature-algorithm-hmac`,
41
 * `web-token/jwt-signature-algorithm-ecdsa` and `web-token/jwt-signature-algorithm-rsa` libraries to be installed for
42
 * JWS verification. This can be done via composer:
43
 *
44
 * ```
45
 * composer require --prefer-dist "web-token/jwt-checker:>=1.0 <3.0" "web-token/jwt-signature:>=1.0 <3.0"
46
 * "web-token/jwt-signature:>=1.0 <3.0" "web-token/jwt-signature-algorithm-hmac:>=1.0 <3.0"
47
 * "web-token/jwt-signature-algorithm-ecdsa:>=1.0 <3.0" "web-token/jwt-signature-algorithm-rsa:>=1.0 <3.0"
48
 * ```
49
 *
50
 * Note: if you are using well-trusted OpenIdConnect provider, you may disable {@see validateJws}, making installation of
51
 * `web-token` library redundant, however it is not recommended as it violates the protocol specification.
52
 *
53
 * @link http://openid.net/connect/
54
 * @see OAuth2
55
 */
56
final class OpenIdConnect extends OAuth2
57
{
58
    protected ?string $scope = 'openid';
59
    /**
60
     * @var string OpenID Issuer (provider) base URL, e.g. `https://example.com`.
61
     */
62
    private string $issuerUrl;
63
    /**
64
     * @var bool whether to validate/decrypt JWS received with Auth token.
65
     * Note: this functionality requires `web-token/jwt-checker`, `web-token/jwt-key-mgmt`, `web-token/jwt-signature`
66
     * composer package to be installed. You can disable this option in case of usage of trusted OpenIDConnect provider,
67
     * however this violates the protocol rules, so you are doing it on your own risk.
68
     */
69
    private bool $validateJws = true;
70
    /**
71
     * @var array JWS algorithms, which are allowed to be used.
72
     * These are used by `web-token` library for JWS validation/decryption.
73
     * Make sure to install `web-token/jwt-signature-algorithm-hmac`, `web-token/jwt-signature-algorithm-ecdsa`
74
     * and `web-token/jwt-signature-algorithm-rsa` packages that support the particular algorithm before adding it here.
75
     */
76
    private array $allowedJwsAlgorithms = [
77
        'HS256',
78
        'HS384',
79
        'HS512',
80
        'ES256',
81
        'ES384',
82
        'ES512',
83
        'RS256',
84
        'RS384',
85
        'RS512',
86
        'PS256',
87
        'PS384',
88
        'PS512',
89
    ];
90
91
    /**
92
     * @var string the prefix for the key used to store {@see configParams} data in cache.
93
     * Actual cache key will be formed addition {@see id} value to it.
94
     *
95
     * @see cache
96
     */
97
    private string $configParamsCacheKeyPrefix = 'config-params-';
98
99
    /**
100
     * @var bool|null whether to use and validate auth 'nonce' parameter in authentication flow.
101
     * The option is used for preventing replay attacks.
102
     */
103
    private ?bool $validateAuthNonce;
104
105
    /**
106
     * @var array OpenID provider configuration parameters.
107
     */
108
    private array $configParams = [];
109
    private CacheInterface $cache;
110
    private string $name;
111
    private string $title;
112
113
    /**
114
     * @var JWSLoader JSON Web Signature
115
     */
116
    private JWSLoader $jwsLoader;
117
    /**
118
     * @var JWKSet Key Set
119
     */
120
    private JWKSet $jwkSet;
121
122
    /**
123
     * OpenIdConnect constructor.
124
     *
125
     * @param string|null $endpoint
126
     * @param $name
127
     * @param $title
128
     * @param ClientInterface $httpClient
129
     * @param RequestFactoryInterface $requestFactory
130
     * @param CacheInterface $cache
131
     * @param StateStorageInterface $stateStorage
132
     * @param SessionInterface $session
133
     */
134
    public function __construct(
135
        $name,
136
        $title,
137
        ClientInterface $httpClient,
138
        RequestFactoryInterface $requestFactory,
139
        CacheInterface $cache,
140
        StateStorageInterface $stateStorage,
141
        SessionInterface $session,
142
        FactoryInterface $factory
143
    ) {
144
        $this->name = $name;
145
        $this->title = $title;
146
        $this->cache = $cache;
147
        parent::__construct($httpClient, $requestFactory, $stateStorage, $session, $factory);
148
    }
149
150
    public function buildAuthUrl(
151
        ServerRequestInterface $incomingRequest,
152
        array $params = []
153
    ): string {
154
        if ($this->authUrl === null) {
155
            $this->authUrl = $this->getConfigParam('authorization_endpoint');
156
        }
157
        return parent::buildAuthUrl($incomingRequest, $params);
158
    }
159
160
    /**
161
     * Returns particular configuration parameter value.
162
     *
163
     * @param string $name configuration parameter name.
164
     *
165
     * @throws InvalidConfigException
166
     * @throws InvalidArgumentException
167
     *
168
     * @return mixed configuration parameter value.
169
     */
170
    public function getConfigParam($name)
171
    {
172
        $params = $this->getConfigParams();
173
        return $params[$name];
174
    }
175
176
    /**
177
     * @throws InvalidConfigException
178
     * @throws InvalidArgumentException
179
     *
180
     * @return array OpenID provider configuration parameters.
181
     */
182
    public function getConfigParams(): array
183
    {
184
        if ($this->configParams === null) {
185
            $cacheKey = $this->configParamsCacheKeyPrefix . $this->getName();
186
            if (($configParams = $this->cache->get($cacheKey)) === null) {
187
                $configParams = $this->discoverConfig();
188
            }
189
190
            $this->configParams = $configParams;
191
            $this->cache->set($cacheKey, $configParams);
192
        }
193
        return $this->configParams;
194
    }
195
196
    /**
197
     * @return string service name.
198
     */
199
    public function getName(): string
200
    {
201
        return 'open_id_connect';
202
    }
203
204
    /**
205
     * Discovers OpenID Provider configuration parameters.
206
     *
207
     * @throws InvalidConfigException
208
     *
209
     * @return array OpenID Provider configuration parameters.
210
     */
211
    private function discoverConfig(): array
212
    {
213
        if ($this->issuerUrl === null) {
214
            throw new InvalidConfigException('Cannot discover config because issuer URL is not set.');
215
        }
216
        $configUrl = $this->issuerUrl . '/.well-known/openid-configuration';
217
        $request = $this->createRequest('GET', $configUrl);
218
        $response = $this->sendRequest($request);
219
220
        return Json::decode($response->getBody()->getContents());
0 ignored issues
show
Bug Best Practice introduced by
The expression return Yiisoft\Json\Json...tBody()->getContents()) could return the type null which is incompatible with the type-hinted return array. Consider adding an additional type-check to rule them out.
Loading history...
221
    }
222
223
    public function fetchAccessToken(ServerRequestInterface $request, $authCode, array $params = []): OAuthToken
224
    {
225
        if ($this->tokenUrl === null) {
226
            $this->tokenUrl = $this->getConfigParam('token_endpoint');
227
        }
228
229
        if (!isset($params['nonce']) && $this->getValidateAuthNonce()) {
230
            $nonce = $this->generateAuthNonce();
231
            $this->setState('authNonce', $nonce);
232
            $params['nonce'] = $nonce;
233
        }
234
235
        return parent::fetchAccessToken($request, $authCode, $params);
236
    }
237
238
    /**
239
     * @throws InvalidConfigException
240
     * @throws InvalidArgumentException
241
     *
242
     * @return bool whether to use and validate auth 'nonce' parameter in authentication flow.
243
     */
244
    public function getValidateAuthNonce(): bool
245
    {
246
        if ($this->validateAuthNonce === null) {
247
            $this->validateAuthNonce = $this->validateJws && in_array(
248
                    'nonce',
249
                    $this->getConfigParam('claims_supported'),
250
                    true
251
                );
252
        }
253
        return $this->validateAuthNonce;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->validateAuthNonce could return the type null which is incompatible with the type-hinted return boolean. Consider adding an additional type-check to rule them out.
Loading history...
254
    }
255
256
    /**
257
     * @param bool $validateAuthNonce whether to use and validate auth 'nonce' parameter in authentication flow.
258
     */
259
    public function setValidateAuthNonce($validateAuthNonce): void
260
    {
261
        $this->validateAuthNonce = $validateAuthNonce;
262
    }
263
264
    /**
265
     * Generates the auth nonce value.
266
     *
267
     * @throws Exception
268
     *
269
     * @return string auth nonce value.
270
     */
271
    protected function generateAuthNonce(): string
272
    {
273
        return Random::string();
274
    }
275
276
    public function refreshAccessToken(OAuthToken $token): OAuthToken
277
    {
278
        if ($this->tokenUrl === null) {
279
            $this->tokenUrl = $this->getConfigParam('token_endpoint');
280
        }
281
        return parent::refreshAccessToken($token);
282
    }
283
284
    /**
285
     * @return string service title.
286
     */
287
    public function getTitle(): string
288
    {
289
        return 'OpenID Connect';
290
    }
291
292
    public function setIssuerUrl(string $url): void
293
    {
294
        $this->issuerUrl = rtrim($url, '/');
295
    }
296
297
    protected function initUserAttributes(): array
298
    {
299
        return $this->api($this->getConfigParam('userinfo_endpoint'), 'GET');
300
    }
301
302
    protected function applyClientCredentialsToRequest(RequestInterface $request): RequestInterface
303
    {
304
        $supportedAuthMethods = $this->getConfigParam('token_endpoint_auth_methods_supported');
305
306
        if (in_array('client_secret_basic', $supportedAuthMethods, true)) {
307
            $request = $request->withHeader(
308
                'Authorization',
309
                'Basic ' . base64_encode($this->clientId . ':' . $this->clientSecret)
310
            );
311
        } elseif (in_array('client_secret_post', $supportedAuthMethods, true)) {
312
            $request = RequestUtil::addParams(
0 ignored issues
show
Bug introduced by
The type Yiisoft\Yii\AuthClient\Client\RequestUtil was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
313
                $request,
314
                [
315
                    'client_id' => $this->clientId,
316
                    'client_secret' => $this->clientSecret,
317
                ]
318
            );
319
        } elseif (in_array('client_secret_jwt', $supportedAuthMethods, true)) {
320
            $header = [
321
                'typ' => 'JWT',
322
                'alg' => 'HS256',
323
            ];
324
            $payload = [
325
                'iss' => $this->clientId,
326
                'sub' => $this->clientId,
327
                'aud' => $this->tokenUrl,
328
                'jti' => $this->generateAuthNonce(),
329
                'iat' => time(),
330
                'exp' => time() + 3600,
331
            ];
332
333
            $signatureBaseString = base64_encode(Json::encode($header)) . '.' . base64_encode(Json::encode($payload));
334
            $signatureMethod = new HmacSha('sha256');
335
            $signature = $signatureMethod->generateSignature($signatureBaseString, $this->clientSecret);
336
337
            $assertion = $signatureBaseString . '.' . $signature;
338
339
            $request = RequestUtil::addParams(
340
                $request,
341
                [
342
                    'assertion' => $assertion,
343
                ]
344
            );
345
        } else {
346
            throw new InvalidConfigException(
347
                'Unable to authenticate request: none of following auth methods is supported: ' . implode(
348
                    ', ',
349
                    $supportedAuthMethods
350
                )
351
            );
352
        }
353
        return $request;
354
    }
355
356
    protected function defaultReturnUrl(ServerRequestInterface $request): string
357
    {
358
        $params = $request->getQueryParams();
359
        // OAuth2 specifics :
360
        unset($params['code'], $params['state'], $params['nonce'], $params['authuser'], $params['session_state'], $params['prompt']);
361
        // OpenIdConnect specifics :
362
363
364
        return $request->getUri()->withQuery(http_build_query($params, '', '&', PHP_QUERY_RFC3986))->__toString();
365
    }
366
367
    protected function createToken(array $tokenConfig = []): OAuthToken
368
    {
369
        if ($this->validateJws) {
370
            $jwsData = $this->loadJws($tokenConfig['params']['id_token']);
371
            $this->validateClaims($jwsData);
372
            $tokenConfig['params'] = array_merge($tokenConfig['params'], $jwsData);
373
374
            if ($this->getValidateAuthNonce()) {
375
                $authNonce = $this->getState('authNonce');
376
                if (!isset($jwsData['nonce']) || empty($authNonce) || strcmp($jwsData['nonce'], $authNonce) !== 0) {
377
                    throw new HttpException('Invalid auth nonce', 400);
378
                }
379
380
                $this->removeState('authNonce');
381
            }
382
        }
383
384
        return parent::createToken($tokenConfig);
385
    }
386
387
    /**
388
     * Decrypts/validates JWS, returning related data.
389
     *
390
     * @param string $jws raw JWS input.
391
     *
392
     * @throws HttpException on invalid JWS signature.
393
     * @throws InvalidArgumentException
394
     *
395
     * @return array JWS underlying data.
396
     */
397
    protected function loadJws(string $jws): array
398
    {
399
        try {
400
            $jwsLoader = $this->getJwsLoader();
401
            $signature = null;
402
            $jwsVerified = $jwsLoader->loadAndVerifyWithKeySet($jws, $this->getJwkSet(), $signature);
403
            return Json::decode($jwsVerified->getPayload());
0 ignored issues
show
Bug Best Practice introduced by
The expression return Yiisoft\Json\Json...Verified->getPayload()) could return the type null which is incompatible with the type-hinted return array. Consider adding an additional type-check to rule them out.
Loading history...
404
        } catch (Exception $e) {
405
            $message = YII_DEBUG ? 'Unable to verify JWS: ' . $e->getMessage() : 'Invalid JWS';
0 ignored issues
show
Bug introduced by
The constant Yiisoft\Yii\AuthClient\Client\YII_DEBUG was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
406
            throw new HttpException($message, $e->getCode(), $e);
407
        }
408
    }
409
410
    /**
411
     * Return JWSLoader that validate the JWS token.
412
     *
413
     * @throws InvalidConfigException on invalid algorithm provide in configuration.
414
     *
415
     * @return JWSLoader to do token validation.
416
     */
417
    protected function getJwsLoader(): JWSLoader
418
    {
419
        if ($this->jwsLoader === null) {
420
            $algorithms = [];
421
            foreach ($this->allowedJwsAlgorithms as $algorithm) {
422
                $class = '\Jose\Component\Signature\Algorithm\\' . $algorithm;
423
                if (!class_exists($class)) {
424
                    throw new InvalidConfigException("Algorithm class $class doesn't exist");
425
                }
426
                $algorithms[] = new $class();
427
            }
428
            $this->jwsLoader = new JWSLoader(
429
                new JWSSerializerManager([new CompactSerializer()]),
430
                new JWSVerifier(new AlgorithmManager($algorithms)),
431
                new HeaderCheckerManager(
432
                    [new AlgorithmChecker($this->allowedJwsAlgorithms)],
433
                    [new JWSTokenSupport()]
434
                )
435
            );
436
        }
437
        return $this->jwsLoader;
438
    }
439
440
    /**
441
     * Return JwkSet, returning related data.
442
     *
443
     * @throws InvalidConfigException
444
     * @throws InvalidArgumentException
445
     *
446
     * @return JWKSet object represents a key set.
447
     */
448
    protected function getJwkSet(): JWKSet
449
    {
450
        if ($this->jwkSet === null) {
451
            $cacheKey = $this->configParamsCacheKeyPrefix . 'jwkSet';
452
            if (($jwkSet = $this->cache->get($cacheKey)) === false) {
453
                $request = $this->createRequest('GET', $this->getConfigParam('jwks_uri'));
454
                $response = $this->sendRequest($request);
455
                $jwkSet = JWKFactory::createFromValues($response);
456
            }
457
458
            $this->jwkSet = $jwkSet;
459
            $this->cache->set($cacheKey, $jwkSet);
460
        }
461
        return $this->jwkSet;
462
    }
463
464
    /**
465
     * Validates the claims data received from OpenID provider.
466
     *
467
     * @param array $claims claims data.
468
     *
469
     * @throws HttpException on invalid claims.
470
     */
471
    protected function validateClaims(array $claims): void
472
    {
473
        if (!isset($claims['iss']) || (strcmp(rtrim($claims['iss'], '/'), rtrim($this->issuerUrl, '/')) !== 0)) {
474
            throw new HttpException('Invalid "iss"', 400);
475
        }
476
        if (!isset($claims['aud']) || (strcmp($claims['aud'], $this->clientId) !== 0)) {
477
            throw new HttpException('Invalid "aud"', 400);
478
        }
479
    }
480
}
481