After successful login into the Admin Panel, note down your customer-id and project-id. These are essential for fetching the JWKS and validating tokens specific to your project.
2. Deserialize the JWT
Extract the JWT sent to your backend and deserialize it to access the headers and payload. This step is crucial for subsequent validation checks.
Use the ClaimCheckerManager to validate standard claims such as issued at (iat), not before (nbf), expiration time (exp), audience (aud), and issuer (iss). Adjust the audience and issuer values according to your application's requirements.
Retrieve the JWKS from Authopia and select the correct key using the kid found in the JWT's header.
Note: To enhance performance and reduce the load on the Authopia servers, implement a caching mechanism to store the JWKS. This way, you don't have to fetch the JWKS for every authentication attempt, only when the cache expires or when the key indicated by the JWT's kid is not found in the cache.
Based on the verification result, take the appropriate action within your application.
if ($isValid) {echo'JWT is valid.';} else {echo'JWT is invalid.';}
Full Example Code
Here's the complete code snippet for reference:
useGuzzleHttp\Client;useJose\Component\Checker\{AlgorithmChecker,AudienceChecker,ClaimCheckerManager,ExpirationTimeChecker,HeaderCheckerManager,IssuedAtChecker,IssuerChecker,NotBeforeChecker};useJose\Component\Core\{AlgorithmManager,JWKSet};useJose\Component\Signature\{JWSTokenSupport,JWSVerifier};useJose\Component\Signature\Algorithm\RS256;useJose\Component\Signature\Serializer\CompactSerializer;// Get Customer ID and Project ID from Admin Panel$customerId ='CUSTOMER-ID';$projectId ='PROJECT-ID';$audience ='YOUR-RP-ID';// Get JWT Token after successful login$jwtToken ='USER-JWT-TOKEN';// Deserialize the JWT to get the header and payload$serializer =newCompactSerializer();$jws = $serializer->unserialize($jwtToken);// Header checks$headerCheckerManager =newHeaderCheckerManager( checkers: [newAlgorithmChecker(['RS256'])], tokenTypes: [newJWSTokenSupport()],);$headerCheckerManager->check( jwt: $jws, index:0, mandatoryHeaderParameters: ['alg','kid'],);// Claim checks$clock =newClock();$claimCheckerManager =newClaimCheckerManager(checkers: [newIssuedAtChecker(allowedTimeDrift: 0, protectedHeaderOnly: true, clock: $clock),newNotBeforeChecker(allowedTimeDrift: 0, protectedHeaderOnly: true, clock: $clock),newExpirationTimeChecker(allowedTimeDrift: 0, protectedHeaderOnly: true, clock: $clock),newAudienceChecker(audience: $audience, protectedHeader: true),newIssuerChecker(issuers: ['api.authopia.io'], protectedHeader: true),]);$claimCheckerManager->check( claims: $claims =json_decode($jws->getPayload(),true), mandatoryClaims: ['iat','nbf','exp','email','projectId'],);// Verify project identifierif ($claims['projectId'] !== $projectId) {thrownew\RuntimeException('Project ID does not match.');}// Fetch the JWKS$client =newClient();$response = $client->get(sprintf('https://api.authopia.io/v1/customers/%s/.well-known/jwks.json', $customerId));$jwks =json_decode($response->getBody()->getContents(),true);$jwkSet =JWKSet::createFromKeyData($jwks);// Get key id (kid) from headers$kid = $jws->getSignature(0)->getProtectedHeader()['kid'];// Match the correct key using 'kid'$key = $jwkSet->get($kid);// Configure JWT verification components$algorithmManager =newAlgorithmManager([newRS256()]);$jwsVerifier =newJWSVerifier($algorithmManager);// Verify the JWT's signature$isValid = $jwsVerifier->verifyWithKey($jws, $key,0);if ($isValid) { $userEmail = $claims['email'];// JWT is verified and validecho'JWT is valid. User email: '. $userEmail;} else {// JWT is invalidecho'JWT is invalid.';}
Follow these steps to securely validate JWTs in your application. Should you encounter any issues or have further questions, feel free to reach out to our support team.