'sha256', 'HS384' => 'sha384', 'HS512' => 'sha512', 'RS256' => 'sha256', 'RS384' => 'sha384', 'RS512' => 'sha512', ); $token = explode('.', $token); if (count($token) < 3) { return array(); } $header = json_decode(base64_decode(strtr($token[0], '-_', '+/')), true); if (!$secret) { return array(); } if ($header['typ'] != 'JWT') { return array(); } $algorithm = $header['alg']; if (!isset($algorithms[$algorithm])) { return array(); } if (!empty($requirements['alg']) && !in_array($algorithm, $requirements['alg'])) { return array(); } $hmac = $algorithms[$algorithm]; $signature = base64_decode(strtr($token[2], '-_', '+/')); $data = "$token[0].$token[1]"; switch ($algorithm[0]) { case 'H': $hash = hash_hmac($hmac, $data, $secret, true); if (function_exists('hash_equals')) { $equals = hash_equals($signature, $hash); } else { $equals = $signature == $hash; } if (!$equals) { return array(); } break; case 'R': $equals = openssl_verify($data, $signature, $secret, $hmac) == 1; if (!$equals) { return array(); } break; } $claims = json_decode(base64_decode(strtr($token[1], '-_', '+/')), true); if (!$claims) { return array(); } foreach ($requirements as $field => $values) { if (!empty($values)) { if ($field != 'alg') { if (!isset($claims[$field]) || !in_array($claims[$field], $values)) { return array(); } } } } if (isset($claims['nbf']) && $time + $leeway < $claims['nbf']) { return array(); } if (isset($claims['iat']) && $time + $leeway < $claims['iat']) { return array(); } if (isset($claims['exp']) && $time - $leeway > $claims['exp']) { return array(); } if (isset($claims['iat']) && !isset($claims['exp'])) { if ($time - $leeway > $claims['iat'] + $ttl) { return array(); } } return $claims; } private function getClaims(string $token): array { $time = (int) $this->getProperty('time', time()); $leeway = (int) $this->getProperty('leeway', '5'); $ttl = (int) $this->getProperty('ttl', '30'); $secret = $this->getProperty('secret', ''); $requirements = array( 'alg' => $this->getArrayProperty('algorithms', ''), 'aud' => $this->getArrayProperty('audiences', ''), 'iss' => $this->getArrayProperty('issuers', ''), ); if (!$secret) { return array(); } return $this->getVerifiedClaims($token, $time, $leeway, $ttl, $secret, $requirements); } private function getAuthorizationToken(ServerRequestInterface $request): string { $headerName = $this->getProperty('header', 'X-Authorization'); $headerValue = RequestUtils::getHeader($request, $headerName); $parts = explode(' ', trim($headerValue), 2); if (count($parts) != 2) { return ''; } if ($parts[0] != 'Bearer') { return ''; } return $parts[1]; } public function process(ServerRequestInterface $request, RequestHandlerInterface $next): ResponseInterface { if (session_status() == PHP_SESSION_NONE) { if (!headers_sent()) { session_start(); } } $token = $this->getAuthorizationToken($request); if ($token) { $claims = $this->getClaims($token); $_SESSION['claims'] = $claims; if (empty($claims)) { return $this->responder->error(ErrorCode::AUTHENTICATION_FAILED, 'JWT'); } if (!headers_sent()) { session_regenerate_id(); } } if (empty($_SESSION['claims'])) { $authenticationMode = $this->getProperty('mode', 'required'); if ($authenticationMode == 'required') { return $this->responder->error(ErrorCode::AUTHENTICATION_REQUIRED, ''); } } return $next->handle($request); } }