Token Complete Examples#
This page groups Token examples by token style so you can compare JWT, signed payload, opaque token and validation helpers in one place.
Create and Verify a Symmetric JWT#
Use this when the issuer and verifier share one secret or a keyed secret set.
<?php
declare(strict_types=1);
use Infocyph\Epicrypt\Security\Policy\SecurityProfile;
use Infocyph\Epicrypt\Token\Jwt\SymmetricJwt;
use Infocyph\Epicrypt\Token\Jwt\Validation\RegisteredClaims;
$now = time();
$claims = [
'iss' => 'issuer-service',
'aud' => 'audience-service',
'sub' => 'subject-service',
'jti' => 'token-1',
'nbf' => $now,
'exp' => $now + 600,
'scope' => 'admin',
'kid' => 'k2',
];
// Use a key id when the verifier may choose among multiple secrets.
$symKeys = ['k1' => 'previous-secret', 'k2' => 'active-secret'];
$sym = SymmetricJwt::forProfile(SecurityProfile::MODERN);
$symToken = $sym->encode($claims, $symKeys);
$symVerifier = SymmetricJwt::forProfile(
SecurityProfile::MODERN,
new RegisteredClaims('issuer-service', 'audience-service', 'subject-service', 'token-1'),
);
$symPayload = $symVerifier->decode($symToken, $symKeys);
$symValid = $symVerifier->verify($symToken, $symKeys);
Create and Verify an Asymmetric JWT#
Use this when one service signs with a private key and others verify with public keys.
<?php
declare(strict_types=1);
use Infocyph\Epicrypt\Certificate\KeyPairGenerator;
use Infocyph\Epicrypt\Security\Policy\SecurityProfile;
use Infocyph\Epicrypt\Token\Jwt\AsymmetricJwt;
use Infocyph\Epicrypt\Token\Jwt\Validation\RegisteredClaims;
$now = time();
$claims = [
'iss' => 'issuer-service',
'aud' => 'audience-service',
'sub' => 'subject-service',
'jti' => 'token-1',
'nbf' => $now,
'exp' => $now + 600,
'scope' => 'admin',
'kid' => 'k2',
];
$rsaA = KeyPairGenerator::openSsl()->generate();
$rsaB = KeyPairGenerator::openSsl()->generate();
$privateSet = ['k1' => $rsaA['private'], 'k2' => $rsaB['private']];
$publicSet = ['k1' => $rsaA['public'], 'k2' => $rsaB['public']];
$asym = AsymmetricJwt::forProfile(SecurityProfile::MODERN);
$asymToken = $asym->encode($claims, $privateSet);
$asymVerifier = AsymmetricJwt::forProfile(
SecurityProfile::MODERN,
new RegisteredClaims('issuer-service', 'audience-service', 'subject-service', 'token-1'),
);
$asymPayload = $asymVerifier->decode($asymToken, $publicSet);
$asymValid = $asymVerifier->verify($asymToken, $publicSet);
Sign a Small Purpose-Bound Payload#
Use this when you want a lightweight signed payload rather than a full JWT.
<?php
declare(strict_types=1);
use Infocyph\Epicrypt\Token\Payload\SignedPayload;
$signedPayload = new SignedPayload('reset_password');
$payloadToken = $signedPayload->encode(['sub' => 'user-1', 'purpose' => 'reset'], 'payload-secret', ['exp' => time() + 600]);
$payloadClaims = $signedPayload->decode($payloadToken, 'payload-secret');
$payloadValid = $signedPayload->verify($payloadToken, 'payload-secret');
Issue an Opaque Token#
Use this when the token should be random and all state should stay on the server.
<?php
declare(strict_types=1);
use Infocyph\Epicrypt\Token\Opaque\OpaqueToken;
$opaque = new OpaqueToken();
$opaqueToken = $opaque->issue(48);
$opaqueDigest = $opaque->hash($opaqueToken);
$opaqueValid = $opaque->verify($opaqueToken, $opaqueDigest);
Resolve Keys Explicitly#
Use this when you manage key sets and need to pick one key by kid.
<?php
declare(strict_types=1);
use Infocyph\Epicrypt\Token\Jwt\KeyResolver;
$symKeys = ['k1' => 'previous-secret', 'k2' => 'active-secret'];
KeyResolver::validate($symKeys, 'k2');
$resolved = KeyResolver::resolve($symKeys, 'k2');
Verify with a Key Ring During Rotation#
Use this when previous and active verification keys must coexist during a short rotation window.
<?php
declare(strict_types=1);
use Infocyph\Epicrypt\Security\KeyRing;
use Infocyph\Epicrypt\Security\Policy\SecurityProfile;
use Infocyph\Epicrypt\Token\Jwt\Enum\SymmetricJwtAlgorithm;
use Infocyph\Epicrypt\Token\Jwt\SymmetricJwt;
use Infocyph\Epicrypt\Token\Jwt\Validation\RegisteredClaims;
$jwt = SymmetricJwt::forProfile(
SecurityProfile::MODERN,
new RegisteredClaims('issuer-service', 'audience-service', 'subject-service', 'token-1'),
);
$ring = new KeyRing([
'previous' => 'previous-secret',
'active' => 'active-secret',
], 'active');
$claims = $jwt->decodeWithAnyKey($token, $ring);
$valid = $jwt->verifyWithAnyKey($token, $ring);
Validate Claims Directly#
Use validator classes when validation needs to be explicit or composable.
<?php
declare(strict_types=1);
use Infocyph\Epicrypt\Token\Jwt\Validation\AudienceValidator;
use Infocyph\Epicrypt\Token\Jwt\Validation\ClaimValidator;
use Infocyph\Epicrypt\Token\Jwt\Validation\ExpirationValidator;
use Infocyph\Epicrypt\Token\Jwt\Validation\IssuerValidator;
use Infocyph\Epicrypt\Token\Jwt\Validation\JwtValidator;
use Infocyph\Epicrypt\Token\Jwt\Validation\RegisteredClaims;
use Infocyph\Epicrypt\Token\Jwt\Validation\SubjectValidator;
$claims = [
'iss' => 'issuer-service',
'aud' => 'audience-service',
'sub' => 'subject-service',
'nbf' => time(),
'exp' => time() + 600,
];
$claimValidator = new ClaimValidator();
$claimValidator->assertRequired($claims, ['iss', 'aud', 'sub', 'nbf', 'exp']);
$claimValidator->assertStringClaim($claims, 'iss');
$registered = RegisteredClaims::fromArray($claims);
(new JwtValidator($registered))->validate($claims);
(new IssuerValidator())->validate('issuer-service', $claims['iss']);
(new AudienceValidator())->validate('audience-service', $claims['aud']);
(new SubjectValidator())->validate('subject-service', $claims['sub']);
(new ExpirationValidator())->validate($claims['nbf'], $claims['exp']);
Use Result APIs for Branching#
Use this when you need structured verification metadata instead of just a boolean.
<?php
declare(strict_types=1);
$jwtResult = $symVerifier->decodeResult($symToken, $symKeys);
$jwtVerified = $jwtResult->verified;
$jwtExpired = $jwtResult->expired;
$jwtKid = $jwtResult->matchedKeyId;
$signedPayloadResult = $signedPayload->verifyWithAnyKeyDetailedResult($payloadToken, $ring);
$payloadVerified = $signedPayloadResult->verified;
$payloadUsedFallback = $signedPayloadResult->usedFallbackKey;
JWKS Export and JWKS-Based Verification#
Use this when asymmetric verifiers receive key material as JWKS.
<?php
declare(strict_types=1);
use Infocyph\Epicrypt\Security\KeyRing;
use Infocyph\Epicrypt\Token\Jwt\AsymmetricJwt;
use Infocyph\Epicrypt\Token\Jwt\Jwks;
$jwksHelper = new Jwks();
$publicRing = new KeyRing($publicSet, 'k2');
$jwks = $jwksHelper->exportFromKeyRing($publicRing);
// Resolve kid -> JWK entry or PEM:
$jwk = $jwksHelper->resolveByKid($jwks, 'k2');
$publicPem = $jwksHelper->importPublicKeyFromJwk($jwk);
// Verify using token kid against JWKS:
$jwksResult = $asymVerifier->verifyFromJwksResult($asymToken, $jwks);
$jwksValid = $jwksResult->verified;