: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
public static function extractTokenContents($token) {
if (!is_string($token)) {
throw new InvalidArgumentException('Token is not a string. ' . gettype($token) . ' given.');
// Verify the token matches the JWT format.
if (!preg_match('/^[a-zA-Z0-9\-_]+?\.[a-zA-Z0-9\-_]+?\.[a-zA-Z0-9\-_]+?$/', $token)) {
throw new wfJWTException('Invalid token format.');
list($header, $body, $signature) = explode('.', $token);
// Test that the token is valid and not expired.
$decodedHeader = base64_decode($header);
if (!(is_string($decodedHeader) && $decodedHeader)) {
throw new wfJWTException('Token header is invalid.');
$header = json_decode($decodedHeader, true);
if (!is_array($header)) {
throw new wfJWTException('Token header is invalid.');
$decodedBody = base64_decode($body);
if (!(is_string($decodedBody) && $decodedBody)) {
throw new wfJWTException('Token body is invalid.');
$body = json_decode($decodedBody, true);
throw new wfJWTException('Token body is invalid.');
'signature' => $signature,
public function __construct($subject = null) {
$this->claims = $this->getClaimDefaults();
$this->claims['sub'] = $subject;
public function encode() {
$header = $this->encodeString($this->buildHeader());
$body = $this->encodeString($this->buildBody());
return sprintf('%s.%s.%s', $header, $body,
$this->encodeString($this->sign(sprintf('%s.%s', $header, $body))));
* @throws wfJWTException|InvalidArgumentException
public function decode($token) {
if (!is_string($token)) {
throw new InvalidArgumentException('Token is not a string. ' . gettype($token) . ' given.');
// Verify the token matches the JWT format.
if (!preg_match('/^[a-zA-Z0-9\-_]+?\.[a-zA-Z0-9\-_]+?\.[a-zA-Z0-9\-_]+?$/', $token)) {
throw new wfJWTException('Invalid token format.');
list($header, $body, $signature) = explode('.', $token);
// Verify signature matches the supplied payload.
if (!$this->verifySignature($this->decodeString($signature), sprintf('%s.%s', $header, $body))) {
throw new wfJWTException('Invalid signature.');
// Test that the token is valid and not expired.
$decodedHeader = base64_decode($header);
if (!(is_string($decodedHeader) && $decodedHeader)) {
throw new wfJWTException('Token header is invalid.');
$header = json_decode($decodedHeader, true);
array_key_exists('alg', $header) &&
$header['alg'] === 'HS256' &&
throw new wfJWTException('Token header is invalid.');
$decodedBody = base64_decode($body);
if (!(is_string($decodedBody) && $decodedBody)) {
throw new wfJWTException('Token body is invalid.');
$body = json_decode($decodedBody, true);
// Check the token not before now timestamp.
array_key_exists('nbf', $body) &&
is_numeric($body['nbf']) &&
$body['nbf'] <= time() &&
// Check the token is not expired.
array_key_exists('exp', $body) &&
is_numeric($body['exp']) &&
$body['exp'] >= time() &&
// Check the issuer and audience is ours.
$body['iss'] === 'Wordfence ' . WORDFENCE_VERSION &&
$body['aud'] === 'Wordfence Central'
throw new wfJWTException('Token is invalid or expired.');
public function sign($string) {
return hash_hmac('sha256', $string, $salt, true);
* @param string $signature
public function verifySignature($signature, $message) {
return hash_equals($this->sign($message), $signature);
public function __toString() {
public function encodeString($data) {
return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
public function decodeString($data) {
return base64_decode(strtr($data, '-_', '+/'));
protected function buildHeader() {
return '{"alg":"HS256","typ":"JWT"}';
protected function buildBody() {
return json_encode($this->getClaims());
protected function getClaimDefaults() {
'iss' => 'Wordfence ' . WORDFENCE_VERSION,
'aud' => 'Wordfence Central',
'exp' => $now + self::JWT_TTL,
public function addClaims($claims) {
if (!is_array($claims)) {
throw new InvalidArgumentException(__METHOD__ . ' expects argument 1 to be array.');
$this->setClaims(array_merge($this->getClaims(), $claims));
public function getClaims() {
public function setClaims($claims) {
class wfJWTException extends Exception {