PHP로 AWS Cognito JWT 디코딩 및 검증
Unearthed에서는 AWS 서비스 Cognito를 사용하여 인증 중에 클라이언트에 JWT를 발급합니다. 거기에서 JWT는 사용자의 신원을 확인하기 위해 사용자가 상호 작용하는 모든 서비스와 교환됩니다. 이는 각 JWT가 사용자 서비스에 대한 직접적인 종속성 없이 인증된 사용자 세션을 설명할 수 있으므로 서비스 그래프를 구축할 때 유용합니다.
PHP에서 Cognito JWT를 디코딩하는 경우 시작하려면 몇 가지 주요 정보가 필요합니다.
us-east-2
). 토큰을 디코딩하기 위해 사용할 토큰web-token/jwt-framework과 함께 설치할 수 있는 몇 가지 다른 종속성:
composer require web-token/jwt-checker web-token/jwt-signature-algorithm-rsa guzzlehttp/guzzle
토큰을 디코딩하고 유효성을 검사하는 프로세스는 다음과 같습니다.
키 다운로드
Cognito 구성은 간단한 값 개체로 나타낼 수 있습니다.
<?php
namespace Sam\JwtBlogPost;
class CognitoConfiguration {
public function __construct(
public readonly string $region,
public readonly string $poolId,
public readonly string $clientId,
) {
}
public function getIssuer(): string {
return sprintf('https://cognito-idp.%s.amazonaws.com/%s_%s', $this->region, $this->region, $this->poolId);
}
public function getPublicKeysUrl(): string {
return sprintf('https://cognito-idp.%s.amazonaws.com/%s_%s/.well-known/jwks.json', $this->region, $this->region, $this->poolId);
}
}
이 구성과 HTTP 클라이언트를 사용하여 키를 다운로드하는 키 관리자를 구현할 수 있습니다.
<?php
declare(strict_types=1);
namespace Sam\JwtBlogPost;
use GuzzleHttp\ClientInterface;
use Jose\Component\Core\JWKSet;
class CognitoKeyManager {
public function __construct(private ClientInterface $client, private CognitoConfiguration $configuration) {
}
public function getKeySet(): JWKSet {
return JWKSet::createFromJson($this->retrieveKeys());
}
private function retrieveKeys(): string {
// @todo These keys can be cached.
return (string) $this->client->request('GET', $this->configuration->getPublicKeysUrl())->getBody();
}
}
클레임 디코딩 및 확인
여기에서 토큰을 디코딩하고 공개 키에 대해 유효성을 검사해야 하며 토큰의 클레임이 유효성을 확인하고 특정 Cognito 사용자 풀에서 생성되었는지 확인해야 합니다.
키 관리자와 구성을 사용하여 Cognito's documentation about how tokens should be decoded and verified 기반으로 작동하는 디코더가 있습니다.
주목해야 할 주요 사항은 다음과 같습니다.
aud
및 client_id
클레임을 확인해야 함). token_use
클레임은 각각 id
또는 access
로 확인되어야 합니다. iat
, nbf
, exp
및 iss
와 같은 다른 표준 클레임은 둘 다에서 확인되어야 합니다. Cognito의 발급자 규칙은 CognitoConfiguration
개체에 캡슐화됩니다.<?php
namespace Sam\JwtBlogPost;
use Jose\Component\Checker\AlgorithmChecker;
use Jose\Component\Checker\AudienceChecker;
use Jose\Component\Checker\ClaimCheckerManager;
use Jose\Component\Checker\ExpirationTimeChecker;
use Jose\Component\Checker\HeaderCheckerManager;
use Jose\Component\Checker\IssuedAtChecker;
use Jose\Component\Checker\IssuerChecker;
use Jose\Component\Checker\NotBeforeChecker;
use Jose\Component\Core\AlgorithmManager;
use Jose\Component\Signature\Algorithm\RS256;
use Jose\Component\Signature\JWS;
use Jose\Component\Signature\JWSLoader;
use Jose\Component\Signature\JWSTokenSupport;
use Jose\Component\Signature\JWSVerifier;
use Jose\Component\Signature\Serializer\CompactSerializer;
use Jose\Component\Signature\Serializer\JWSSerializerManager;
use Sam\JwtBlogPost\Checkers\ClientIdChecker;
use Sam\JwtBlogPost\Checkers\TokenUseChecker;
/**
* Load and verify Cognito tokens.
*
* Rules for verifying tokens are:
* - Verify that the token is not expired.
* - The aud claim in an ID token and the client_id claim in an access token should match the app client ID that was created in the Amazon Cognito user pool.
* - The issuer (iss) claim should match your user pool. For example, a user pool created in the us-east-1 Region will have the following iss value: https://cognito-idp.us-east-1.amazonaws.com/<userpoolID>.
* - Check the token_use claim.
* - If you are only accepting the access token in your web API operations, its value must be access.
* - If you are only using the ID token, its value must be id.
* - If you are using both ID and access tokens, the token_use claim must be either id or access.
*
* @see https://web-token.spomky-labs.com/advanced-topics-1/security-recommendations#loading-process
* @see https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-verifying-a-jwt.html
*/
class CognitoJwtDecoder {
public function __construct(private CognitoKeyManager $keyManager, private CognitoConfiguration $configuration) {
}
public function decodeIdToken(string $token): JWS {
return $this->decodeAndValidate($token, [
new AudienceChecker($this->configuration->clientId),
new TokenUseChecker('id'),
], ['iss', 'aud', 'token_use']);
}
public function decodeAccessToken(string $token): JWS {
return $this->decodeAndValidate($token, [
new ClientIdChecker($this->configuration->clientId),
new TokenUseChecker('access'),
], ['iss', 'client_id', 'token_use']);
}
/**
* @throws \Jose\Component\Checker\InvalidClaimException
* @throws \Jose\Component\Checker\MissingMandatoryClaimException
* @throws \Exception
*/
private function decodeAndValidate(string $token, array $claimChecks, array $mandatoryClaims): JWS {
$headerChecker = new HeaderCheckerManager([new AlgorithmChecker(['RS256'])], [new JWSTokenSupport()]);
$claimChecker = new ClaimCheckerManager(
array_merge([
new IssuedAtChecker(),
new NotBeforeChecker(),
new ExpirationTimeChecker(),
new IssuerChecker([$this->configuration->getIssuer()]),
], $claimChecks)
);
$loader = new JWSLoader(new JWSSerializerManager([new CompactSerializer()]), new JWSVerifier(new AlgorithmManager([new RS256()])), $headerChecker);
$jws = $loader->loadAndVerifyWithKeySet($token, $this->keyManager->getKeySet($token), $signature);
$claims = json_decode($jws->getPayload(), true);
$claimChecker->check($claims, $mandatoryClaims);
return $jws;
}
}
모두 함께 당기기
이러한 구성 요소를 모두 갖추고 있으면 Cognito JWT를 검증하고 디코딩할 수 있는 개념 증명을 함께 가져올 수 있습니다.
<?php
require_once 'vendor/autoload.php';
[, $region, $poolId, $clientId, $type, $token] = $argv;
$config = new \Sam\JwtBlogPost\CognitoConfiguration($region, $poolId, $clientId);
$keyManager = new \Sam\JwtBlogPost\CognitoKeyManager(
new \GuzzleHttp\Client(),
$config,
);
$decoder = new \Sam\JwtBlogPost\CognitoJwtDecoder($keyManager, $config);
var_export($type === 'access' ? $decoder->decodeAccessToken($token) : $decoder->decodeIdToken($token));
다음과 같이 호출할 수 있습니다.
php run.php us-east-2 POOL_ID CLIENT_ID TOKEN_TYPE TOKEN
디코딩된 토큰 생성:
<?php
Jose\Component\Signature\JWS::__set_state(array(
'payload' => '{"sub":"420cd5cc-f537-4eab-a338-dc72f0b048e0","aud"...
Symfony를 사용하는 경우 이 블로그 게시물에 사용된 공장 및 서비스 중 일부를 컨테이너에서 사용할 수 있도록 하는 Symfony Bundle이 있다는 점을 언급할 가치가 있습니다. 우리 애플리케이션에서는 이러한 종속성을 직접 인스턴스화하는 것이 바람직하다고 결정했습니다.
Reference
이 문제에 관하여(PHP로 AWS Cognito JWT 디코딩 및 검증), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/unearthed/decoding-and-validating-aws-cognito-jwts-with-php-3825텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)