Assuming that I received token after managed to login through openid-connect
http://xxxxxx/auth/realms/demo/protocol/openid-connect/token
{
"access_token": "xxxxxx",
"expires_in": 600,
"refresh_expires_in": 1800,
"refresh_token": "xxxxxx",
"token_type": "bearer",
"not-before-policy": xxxx,
"session_state": "xxxxx",
"scope": "email profile"
}
Is there any ways on how to decode the payload of the jwt tokens just like the https://jwt.io/ did , using PHP? Thank you.
You can use this library https://github.com/firebase/php-jwt.
Why do you want to decode the access_token though? Usually it's the id_token that gets decoded so that the client can verify the end-user's identity. The process of decoding requires the JWT to have its signature verified.
You can use the library I mentioned above. The steps are easy. You need:
The JWT
Secret Key/ Public Key
Algorithm used to encode the JWT
The following snippet is used to decode + verify a JWT. It uses HS256 so a secret key must be in the possession of the client:
$decoded = JWT::decode($jwt, $key, array('HS256'));
If you want to decode a JWT without verifying its signature (unsafe), you can create a function that separates each of the JWT section: header, body, and signature, and base64url decode it. Like so:
// Pass in the JWT, and choose which section. header = 0; body = 1; signature = 2
public function decodeJWT($jwt, $section = 0) {
$parts = explode(".", $jwt);
return json_decode(base64url_decode($parts[$section]));
}
EDIT if you're decoding + verifying an id_token which uses assymetric algorithm e.g. RSA256, RSA384 etc, you need the public key. OpenID Connect defines a JWK Set endpoint (/.well-known/jwks.json), which lists the public keys in JWK format. You can hit that endpoint and save the response in an array. In order to find which public key was used, the JWK has a kid claim/ property. Which represents the key id, the identifier of the public key. You can decode your id_token and grab its header using :
$header = decodeJWT($id_token, 0);
Then you can pass the header to the function below to get the key that was used to encode the id_token. Parameter $keys holds the JWK Set response:
function getIdTokenKey($keys, $header) {
foreach ($keys as $key) {
if ($key->kty == 'RSA') {
if (!isset($header->kid) || $key->kid == $header->kid) {
return $key;
}
}
}
throw new Exception("key not found");
}
$key = getIdTokenKey($keys, $header);
Finally call the decode function, assume it's using RSA256:
$decoded = JWT::decode($id_token, $key, array('RSA256'));
Edit(2) On another note it's the same process to decode any JWT, be it an access token, id token, or arbitrary data being passed to different entities in a server environment.
Related
i'm using the Cognito authorization code to get my access tokens from AWS Cognito. So this is my current workflow:
No session data, forward user to hosted UI.
On login, return to PHP Application with the authorization code.
Use authorization code to get the tokens.
Validate the tokens using the jwk tokens.
So step 4 is where i'm stuck, as when validating the tokens, JWT is starting that i'm trying to decode the access_token before it is valid:
Cannot handle token prior to 2022-05-26T13:45:17+0000
I have dumped out the code which displays this error to get the iat time and the time that it is being compared against:
dd($payload->iat, ($timestamp + static::$leeway));
This outputs:
1653576011 1653576009
So there is a 0000000002 difference...
Now I can fix this by changing leeway to 10, but this doesn't seem the correct thing to do... any ideas?
Below is the code:
private function validateTokens($accessToken): bool
{
$domain = implode('.', [ 'cognito-idp', $this->region, 'amazonaws.com' ]);
$jwks = file_get_contents("https://$domain/{$this->pool_id}/.well-known/jwks.json");
$jwks = collect(json_decode($jwks, true, 512, JSON_THROW_ON_ERROR)['keys']);
$jwks = $jwks->keyBy('kid')->map(static function ($current) {
return (new JWKConverter())->toPEM($current);
})->toArray();
$jwt = new JWT();
$jwt::$leeway = 10;
$decoded = $jwt::decode($accessToken['access_token'], $jwks, ['RS256']);
dd($decoded);
How can I validate a X-HW-SIGNATURE in PHP?
The documentation for request parameters reads:
Message header signature, which is mandatory, indicating the
signature information sent to your server that receives uplink messages.
There's also example data:
timestamp=1563105451261; nonce=:; value=E4YeOsnMtHZ6592U8B9S37238E+Hwtjfrmpf8AQXF+c=
The keys are:
timestamp: standard Unix timestamp
nonce: colon
value: character string to be encrypted
This here is the part which I don't understand:
timestamp + nonce + Uplink message content: obtained after the encryption using the set password in HMAC-SHA256 algorithm and encoding in Base64.
How can I validate the message payload against the header signature?
What I've tried so far basically is:
private function parse_request_body(): void {
$this->rawBody = stream_get_contents(STDIN);
if (isset($_SERVER['X-HW-SIGNATURE']) && !empty($_SERVER['X-HW-SIGNATURE'])) {
if (! $this->hmac_verify( $this->rawBody, $_SERVER['X-HW-SIGNATURE'] )) {
// spoof message
}
}
}
private function hmac_verify( string $payload, string $signature ): bool {
// the problem obviously lies here ...
return true;
}
This is how i would go about verifying the signature. From my understanding from the doc. However it isn't 100% clear as they do not provide an example, which is a shame...
You should have (or be able to create one) a secret key within your Huawei account somewhere.
private function hmac_verify( string $payload, string $signature ): bool
{
$secretKey = 'yoursecretkey';
$parsedSignature = str_replace(';', '&', $signature); //'timestamp=1563105451261& nonce=:& value=E4YeOsnMtHZ6592U8B9S37238E+Hwtjfrmpf8AQXF+c='
parse_str($parsedSignature, $signatureParts);
// $signatureParts
//
// array(3) {
// ["timestamp"]=>
// string(13) "1563105451261"
// ["nonce"]=>
// string(1) ":"
// ["value"]=>
// string(44) "E4YeOsnMtHZ6592U8B9S37238E Hwtjfrmpf8AQXF c="
// }
$signed = hash_hmac("sha256", $signatureParts['timestamp'] + $signatureParts['nonce'] + $payload, $secretKey);
return base64_encode($signed) === $signatureParts['value'];
}
On another page of the documentation (X-HUAWEI-CALLBACK-ID), I've found a similar description:
Base64-encoded string that has been HMAC-SHA256 encrypted using the callback key. The string before encryption consists of the value of timestamp, value of nonce, and callback user name, without plus signs.
And here it's being described how to send push.hcm.upstream messages on Android. Sending an upstream message might be the best chance to obtain the payload, in order to validate a signature. The server-side procedure upon send as following:
When receiving the uplink message, the Push Kit server will:
Combine the receiving timestamp, colon (:), and uplink message into a character array to be encrypted (for example, 123456789:your_data).
Encrypt the character array in HMAC-SHA256 mode using an HMAC signature verification key, and encode the encrypted result in Base64 to generate a signature.
Transfer the signature and timestamp information to your app server through the X-HW-SIGNATURE and X-HW-TIMESTAMP fields in the HTTPS request header.
Your app server needs to use the HTTPS request header and HMAC signature verification key to verify the validity of the uplink message.
Whatever "an HMAC signature verification key" may be; placeholder your_data sounds alike, as if (likely not yet base64 encoded) $payload->data would have been used to generate the signature:
/** Concatenate the input string, generate HMAC hash with SHA256 algorithm, then encode as base64. */
private function generate_signature( int $timestamp, string $nonce, string $data_str, string $secret_key): string {
$input = $timestamp.$nonce.$data_str;
$hmac = hash_hmac( 'sha256', $input, $secret_key );
return base64_encode( $hmac );
}
/** Convert the received signature string to object. */
private function to_object( string $signature ): stdClass {
$input = str_getcsv( $signature, '; ' );
$data = new stdClass();
$data->timestamp = (int) str_replace('timestamp=', '', $input[0]);
$data->nonce = (string) str_replace( ' nonce=', '', $input[1]);
$data->value = (string) str_replace( ' value=', '', $input[2]);
return $data;
}
public function hmac_verify( string $raw_body, string $secret_key, string $signature ): bool {
/* Extract data-string from the raw body. */
$payload = json_decode( $raw_body );
$data_str = base64_decode( $payload->data );
/* Convert the received signature string to object. */
$signature = $this->to_object( $signature );
/* Generate a signature which to compare to. */
$generated = $this->generate_signature( $signature->timestamp, $signature->nonce, $data_str, $secret_key);
/* Compare the generated with the received signature. */
return $generated === $signature->value;
}
Need to test this once with an actual $_POST ...
The "HMAC signature verification key" (per web-hook) can be obtained from the PushKit console:
Thank you for providing the information regarding this issue. We are very sorry that it brings you inconvinience and are now organizing R&D team to supplement the sample code.
The X-HW-SIGNATURE field is used to check whether the message is from Huawei service.
Usage:
Timestamp + nonce + Uplink message content are combined into a character string. Use the configured HMAC HMAC-SHA256 algorithm and encoding in Base64 to compare the obtained value with the value sent by the push service. If they are the same, the message is from the push service, and you do not need to parse the specific value of this field.
Context: I want to implement payment with Payconiq. When the payment is done, Payconiq calls my API to give me payment information (status, etc).
I'm using Symfony and web-token/jwt-bundle to verify JWS.
1/ I use 'base64_decode' to get the header from the token (token format is like: header.payload.signature with an empty payload)
2/ I get the json JWKs from URL: the JWK that always seems to be used is like:
{
"kty": "EC",
"use": "sig",
"x5t#S256": "******************",
"crv": "P-256",
"kid": "kid.2021",
"alg": "ES256",
"x5c": [],
"x": *******,
"y": *******
3/ I want to verify the signature with this JWK. I do :
$serializerManager = new JWSSerializerManager([new CompactSerializer(),]);
$jws = $serializerManager->unserialize($token);
$isVerified = $jwsVerifier->verifyWithKey($jws, $jwk, 0, $payload);
(public function verifyWithKey(JWS $jws, JWK $jwk, int $signature, ?string $detachedPayload = null): bool)
My payload: body request sent by Payconiq (payment information).
$isVerified is always false.
I don't know if the problem comes from my payload or the way I use the library (documentation shows an example with a JWK like
{
"kty": "oct",
"k": "dzI6nbW4OcNF-AtfxGAmuyz7IpHRudBI0WgGjZWgaRJt6prBn3DARXgUR8NVwKhfL43QBIU2Un3AvCGCHRgY4TbEqhOi8-i98xxmCggNjde4oaW6wkJ2NgM3Ss9SOX9zS3lcVzdCMdum-RwVJ301kbin4UtGztuzJBeg5oVN00MGxjC2xWwyI0tgXVs-zJs5WlafCuGfX1HrVkIf5bvpE0MQCSjdJpSeVao6-RSTYDajZf7T88a2eVjeW31mMAg-jzAWfUrii61T_bYPJFOXW8kkRWoa1InLRdG6bKB9wQs9-VdXZP60Q4Yuj_WZ-lO7qV9AEFrUkkjpaDgZT86w2g'
}
There's is a "k" key and the result is ok (isVerified = true).
But with a JWK without "k" and with "x5c", isVerified still false.
Could someone please help me?
It looks like the verification failed because you have have forgotten to set the appropriate signature algorithm (ES256) in the $jwsVerifier object.
Find hereafter a valid example. Please change the JWK and token values with you data.
use Jose\Component\Core\AlgorithmManager;
use Jose\Component\Core\JWK;
use Jose\Component\Signature\Algorithm\ES256;
use Jose\Component\Signature\Serializer\CompactSerializer;
use Jose\Component\Signature\JWSVerifier;
$jwk = JWK::createFromJson('{"kty":"EC","crv":"P-256","x":"f83OJ3D2xF1Bg8vub9tLe1gHMzV76e8Tus9uPHvRVEU","y":"x_FEzRu9m36HLN_tue659LNpXW6pCyStikYjKIWI5a0"}');
$token = 'eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.DtEhU3ljbEg8L38VWAfUAqOyKAM6-Xx-F4GawxaepmXFCgfTjDxw5djxLa8ISlSApmWQxfKTUJqPP3-Kg6NU1Q';
$serializerManager = new CompactSerializer();
$jws = $serializerManager->unserialize($token);
$algorithmManager = new AlgorithmManager([new ES256()]);
$jwsVerifier = new JWSVerifier($algorithmManager);
$isVerified = $jwsVerifier->verifyWithKey($jws, $jwk, 0);
if ($isVerified) {
var_dump('Signature is valid');
} else {
var_dump('Signature is NOT valid!');
}
In case the payload is detached from the token, you can set it as fourth parameter of the verifyWithKey method.
Note that it shall not be base 64 encoded.
<?php
use Jose\Component\Core\AlgorithmManager;
use Jose\Component\Core\JWK;
use Jose\Component\Signature\Algorithm\ES256;
use Jose\Component\Signature\Serializer\CompactSerializer;
use Jose\Component\Signature\JWSVerifier;
$jwk = JWK::createFromJson('{"kty":"EC","crv":"P-256","x":"f83OJ3D2xF1Bg8vub9tLe1gHMzV76e8Tus9uPHvRVEU","y":"x_FEzRu9m36HLN_tue659LNpXW6pCyStikYjKIWI5a0"}');
$token = 'eyJhbGciOiJFUzI1NiJ9..DtEhU3ljbEg8L38VWAfUAqOyKAM6-Xx-F4GawxaepmXFCgfTjDxw5djxLa8ISlSApmWQxfKTUJqPP3-Kg6NU1Q';
$payload = base64_decode('eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ');
$serializerManager = new CompactSerializer();
$jws = $serializerManager->unserialize($token);
$algorithmManager = new AlgorithmManager([new ES256()]);
$jwsVerifier = new JWSVerifier($algorithmManager);
$isVerified = $jwsVerifier->verifyWithKey($jws, $jwk, 0, $payload);
if ($isVerified) {
var_dump('Signature is valid');
} else {
var_dump('Signature is NOT valid!');
}
I'm trying to validate a Google Play/Android In App Product consumed purchase server-side using PHP. I get a response back with a valid receipt, but there are two confusing issues:
The productId is always null
If I change the the $productId in the sample below to an invalid ID, it will return the exact same response. This seems to be the case for literally any string.
Here is my sample code:
$purchaseToken = 'TEST purchaseToken FROM ANDROID APP';
$appId = 'com.example.myapp';
$productId = 'com.example.myapp.iap1';
$googleClient = new \Google_Client();
$googleClient->setScopes([\Google_Service_AndroidPublisher::ANDROIDPUBLISHER]);
$googleClient->setApplicationName($appId);
$googleClient->setAuthConfig(__DIR__ . '/gp-service.json');
$googleAndroidPublisher = new \Google_Service_AndroidPublisher($googleClient);
$purchase = $googleAndroidPublisher->purchases_products->get($appId, $productId, $purchaseToken);
If I dump out $purchase, I get:
=> Google_Service_AndroidPublisher_ProductPurchase {
+acknowledgementState: 1,
+consumptionState: 1,
+developerPayload: "",
+kind: "androidpublisher#productPurchase",
+obfuscatedExternalAccountId: null,
+obfuscatedExternalProfileId: null,
+orderId: "GPA.XXXX-XXXX-XXXX-XXXXX",
+productId: null,
+purchaseState: 0,
+purchaseTimeMillis: "1602771022178",
+purchaseToken: null,
+purchaseType: 0,
+quantity: null,
+regionCode: "US",
}
Does anyone know what I am doing wrong here? It doesn't seem to be validating the productId on its end nor does it provide me the data I would need to validate it on my end, meaning I have no way of validating this IAP right now.
https://issuetracker.google.com/issues/169870112
I've found on google issue tracker that ignoring productId is an intended behaviour. I've wrote post asking if the null that we receive in response is also an intended behaviour. I hope not because as you wrote if productId will be always null we have no way of fully validating IAP right now.
$purchaseToken was undefined in Josh's answer.
<?php
$appId = "com.example.myapp";
$serviceAccountJson = __DIR__ . "/gp-service.json";
// this is the raw receipt data received on the device from Google Play; this example is obfuscated and only shows the keys for sensitive fields
$googlePlayReceipt =
'{"productId": "com.example.myapp.iap1","transactionDate": 1602714720893,"transactionReceipt": "","purchaseToken": "","transactionId": "","dataAndroid": "","signatureAndroid": "","isAcknowledgedAndroid": false,"autoRenewingAndroid": false,"purchaseStateAndroid": 1}';
// decode the json to an array we can use
$decodedGooglePlayReceipt = json_decode($googlePlayReceipt, true);
// the data that was signed for verification purposes
$data = $decodedGooglePlayReceipt["transactionReceipt"];
// the signature that was used to sign the $data
$signature = $decodedGooglePlayReceipt["signatureAndroid"];
// The "Base64-encoded RSA public key" for your app, taken from the Google Play Console
// In the Classic Console: Your App -> Development Tools -> Services & APIs -> Licensing & in-app billing
// In the New Console: Your App -> Monetize -> Monetization Setup -> Licensing
$base64EncodedPublicKeyFromGoogle = "################";
// Convert the key into the normal public key format
// Just need to split the base64 key into 64 character long lines and add the usual prefix/suffix
$openSslFriendlyKey =
"-----BEGIN PUBLIC KEY-----\n" .
chunk_split($base64EncodedPublicKeyFromGoogle, 64, "\n") .
"-----END PUBLIC KEY-----";
// Convert the key to the openssl key ID that openssl_verify() expects
// I'm unsure if this step would be necessary on all platforms
$publicKeyId = openssl_get_publickey($openSslFriendlyKey);
// Use openssl_verify() to verify the $signature (which has to be base64 decoded!) against the $data using the public key we have
$result = openssl_verify(
$data,
base64_decode($signature),
$publicKeyId,
OPENSSL_ALGO_SHA1
);
if ($result === 0) {
throw new Exception("Invalid receipt");
}
if ($result !== 1) {
throw new Exception(openssl_error_string());
}
// receipt data is valid. now let's grab the productId and purchaseToken
$decodedData = json_decode($data, true);
$purchasedProductId = decodedData["productId"];
$purchaseToken = decodedData["purchaseToken"];
// now we'll verify that the receipt is valid for our account
try {
$googleClient = new \Google_Client();
$googleClient->setScopes([
\Google_Service_AndroidPublisher::ANDROIDPUBLISHER,
]);
$googleClient->setApplicationName($appId);
$googleClient->setAuthConfig($serviceAccountJson);
$googleAndroidPublisher = new \Google_Service_AndroidPublisher(
$googleClient
);
$purchase = $googleAndroidPublisher->purchases_products->get(
$appId,
$purchasedProductId,
$purchaseToken
);
} catch (Throwable $exception) {
// this means the receipt data is unable to be validated by Google
throw new Exception("Invalid receipt");
}
After seeing Deusald's response here and starting to type up a response to the Google Issues ticket complaining about it, I had an epiphany: Google is just validating that the transaction is valid for your account and expects you to validate the receipt data server-side. They include a base64 encoded RSA SHA1 signature in the receipt data and the original data they used to create that signature, so they give you everything you need to accomplish this.
The below snippet accomplishes that verification for PHP, but it should be easily portable to other languages:
<?php
// our app's bundle id
$appId = 'com.example.myapp';
// the location of a Service Account JSON file for a Service account that has access to the "Financial Data" permissions in the Play Console
$serviceAccountJson = __DIR__ . '/gp-service.json';
// this is the raw receipt data received on the device from Google Play; this example is obfuscated and only shows the keys for sensitive fields
$googlePlayReceipt = '{"productId": "com.example.myapp.iap1","transactionDate": 1602714720893,"transactionReceipt": "","purchaseToken": "","transactionId": "","dataAndroid": "","signatureAndroid": "","isAcknowledgedAndroid": false,"autoRenewingAndroid": false,"purchaseStateAndroid": 1}';
// decode the json to an array we can use
$decodedGooglePlayReceipt = json_decode($googlePlayReceipt, true);
// the data that was signed for verification purposes
$data = $decodedGooglePlayReceipt['transactionReceipt'];
// the signature that was used to sign the $data
$signature = $decodedGooglePlayReceipt['signatureAndroid'];
// The "Base64-encoded RSA public key" for your app, taken from the Google Play Console
// In the Classic Console: Your App -> Development Tools -> Services & APIs -> Licensing & in-app billing
// In the New Console: Your App -> Monetize -> Monetization Setup -> Licensing
$base64EncodedPublicKeyFromGoogle = '################';
// Convert the key into the normal public key format
// Just need to split the base64 key into 64 character long lines and add the usual prefix/suffix
$openSslFriendlyKey = "-----BEGIN PUBLIC KEY-----\n" . chunk_split($base64EncodedPublicKeyFromGoogle, 64, "\n") . "-----END PUBLIC KEY-----";
// Convert the key to the openssl key ID that openssl_verify() expects
// I'm unsure if this step would be necessary on all platforms
$publicKeyId = openssl_get_publickey($openSslFriendlyKey);
// Use openssl_verify() to verify the $signature (which has to be base64 decoded!) against the $data using the public key we have
$result = openssl_verify($data, base64_decode($signature), $publicKeyId, OPENSSL_ALGO_SHA1);
if ($result === 1) {
// receipt data is valid. now let's grab the productId and purchaseToken
$decodedData = json_decode($data, true);
$purchasedProductId = decodedData['productId'];
$purchaseToken = decodedData['purchaseToken'];
// now we'll verify that the receipt is valid for our account
try {
$googleClient = new \Google_Client();
$googleClient->setScopes([\Google_Service_AndroidPublisher::ANDROIDPUBLISHER]);
$googleClient->setApplicationName($appId);
$googleClient->setAuthConfig($serviceAccountJson);
$googleAndroidPublisher = new \Google_Service_AndroidPublisher($googleClient);
$purchase = $googleAndroidPublisher->purchases_products->get($appId, $purchasedProductId, $purchaseToken);
} catch (Throwable $exception) {
// this means the receipt data is unable to be validated by Google
throw new Exception('Invalid receipt');
}
} elseif ($result === 0) {
throw new Exception('Invalid receipt');
} else {
throw new Exception(openssl_error_string());
}
In PHP, I'm trying to validate an AWS auth token (JWT returned from getOpenIdTokenForDeveloperIdentity) using the AWS's RSA public key (which I generated from modulus/exponent at https://cognito-identity.amazonaws.com/.well-known/jwks_uri). The key begins with the appropriate headers/footers -----BEGIN RSA PUBLIC KEY----- etc. I've looked at a few PHP libraries like Emarref\Jwt\Jwt, however I get the error: error:0906D06C:PEM routines:PEM_read_bio:no start line. It all boils down to the basic php function: openssl_verify.
I've looked at the php.net/manual for openssl-verify, but I'm still not clear on the parameter details. The algorithm needed is RS512.
I am able to verify the JWT token using node.js with no problems (same key and token). For that I used the library: https://github.com/auth0/node-jsonwebtoken
Not sure why this doesn't work in PHP. Can I not use an RSA Public Key?
function verifyKey($public_key) {
$jwt = new Emarref\Jwt\Jwt();
$algorithm = new Emarref\Jwt\Algorithm\Rs512();
$factory = new Emarref\Jwt\Encryption\Factory();
$encryption = $factory->create($algorithm);
$encryption->setPublicKey($public_key);
$context = new Emarref\Jwt\Verification\Context($encryption);
$token = $jwt->deserialize($authToken);
try {
$jwt->verify($token, $context);
} catch (Emarref\Jwt\Exception\VerificationException $e) {
debug($e->getMessage());
}
}
Could you try using another PHP library: https://github.com/Spomky-Labs/jose
// File test.php
require_once __DIR__.'/vendor/autoload.php';
use Jose\Checker\ExpirationChecker;
use Jose\Checker\IssuedAtChecker;
use Jose\Checker\NotBeforeChecker;
use Jose\Factory\KeyFactory;
use Jose\Factory\LoaderFactory;
use Jose\Factory\VerifierFactory;
use Jose\Object\JWKSet;
use Jose\Object\JWSInterface;
// We create a JWT loader.
$loader = LoaderFactory::createLoader();
// We load the input
$jwt = $loader->load($input);
if (!$jws instanceof JWSInterface) {
die('Not a JWS');
}
// Please note that at this moment the signature and the claims are not verified
// To verify a JWS, we need a JWKSet that contains public keys (from RSA key in your case).
// We create our key object (JWK) using a RSA public key
$jwk = KeyFactory::createFromPEM('-----BEGIN RSA PUBLIC KEY-----...');
// Then we set this key in a keyset (JWKSet object)
// Be careful, the JWKSet object is immutable. When you add a key, you get a new JWKSet object.
$jwkset = new JWKSet();
$jwkset = $jwkset->addKey($jwk);
// We create our verifier object with a list of authorized signature algorithms (only 'RS512' in this example)
// We add some checkers. These checkers will verify claims or headers.
$verifier = VerifierFactory::createVerifier(
['RS512'],
[
new IssuedAtChecker(),
new NotBeforeChecker(),
new ExpirationChecker(),
]
);
$is_valid = $verifier->verify($jws, $jwkset);
// The variable $is_valid contains a boolean that indicates the signature is valid or not.
// If a claim is not verified (e.g. the JWT expired), an exception is thrown.
//Now you can use the $jws object to retreive all claims or header key/value pairs
I was able to get this library to work. However I had to build the key using KeyFactory::createFromValues instead of KeyFactory::createFromPEM. THANK YOU!