_payload = $payload; $this->_expiration = $expiration; } public function __toString() { $payload = $this->_payload; if ($this->_expiration !== false) { $payload['_exp'] = $this->_expiration; } $key = Model_Crypto::shared_hash_secret(); $header = '{"alg":"HS256","typ":"JWT"}'; $body = self::base64url_encode($header) . '.' . self::base64url_encode(json_encode($payload)); $signature = hash_hmac('sha256', $body, $key, true); return $body . '.' . self::base64url_encode($signature); } public function __isset($key) { switch ($key) { case 'payload': case 'expiration': return true; } throw new \OutOfBoundsException('Invalid key: ' . $key); } public function __get($key) { switch ($key) { case 'payload': return $this->_payload; case 'expiration': return $this->_expiration; } throw new \OutOfBoundsException('Invalid key: ' . $key); } /** * Utility */ /** * Base64URL-encodes the given payload. This is identical to base64_encode except it substitutes characters * not safe for use in URLs. * * @param string $payload * @return string */ public static function base64url_encode($payload) { return self::base64url_convert_to(base64_encode($payload)); } public static function base64url_convert_to($base64) { $intermediate = rtrim($base64, '='); $intermediate = str_replace('+', '-', $intermediate); $intermediate = str_replace('/', '_', $intermediate); return $intermediate; } /** * Base64URL-decodes the given payload. This is identical to base64_encode except it allows for the characters * substituted by base64url_encode. * * @param string $payload * @return string */ public static function base64url_decode($payload) { return base64_decode(self::base64url_convert_from($payload)); } public static function base64url_convert_from($base64url) { $intermediate = str_replace('_', '/', $base64url); $intermediate = str_replace('-', '+', $intermediate); return $intermediate; } }