diff --git a/src/AblyBroadcaster.php b/src/AblyBroadcaster.php index c913800..f8f40df 100644 --- a/src/AblyBroadcaster.php +++ b/src/AblyBroadcaster.php @@ -74,7 +74,9 @@ public function __construct(AblyRest $ably, $config) } /** - * @return int + * Get the current server time adjusted by the Ably server time difference (if clock difference exists). + * + * @return int The current server time in seconds. */ private function getServerTime() { @@ -212,11 +214,19 @@ public function getSignedToken($channelName, $token, $clientId, $guardedChannelC $serverTimeFn = function () { return $this->getServerTime(); }; - if ($token && Utils::isJwtValid($token, $serverTimeFn, $this->getPrivateToken())) { + if ($token && Utils::isJwtValid($token, $serverTimeFn, $this->getPrivateToken()) && Utils::isSameUser($token, $clientId)) { $payload = Utils::parseJwt($token)['payload']; $iat = $payload['iat']; $exp = $payload['exp']; $channelClaims = json_decode($payload['x-ably-capability'], true); + + // Check if the token is about to expire and renew it if necessary + // The Laravel Echo client typically initiates token renewal 30 seconds before expiry + // Spec: RTN22 + if ($exp - $serverTimeFn() <= 30) { + $iat = $serverTimeFn(); + $exp = $iat + $this->tokenExpiry; + } } else { $iat = $serverTimeFn(); $exp = $iat + $this->tokenExpiry; diff --git a/src/Utils.php b/src/Utils.php index b3c8c9f..36fd399 100644 --- a/src/Utils.php +++ b/src/Utils.php @@ -104,4 +104,19 @@ public static function decodeSocketId($socketId): ?object } return $socketIdObject; } + + public static function isSameUser($token, $clientId) + { + // Decode the JWT token to extract the payload + $decodedToken = Utils::parseJwt($token); + $payload = $decodedToken['payload']; + + // Check if the clientId in the payload matches the provided clientId + if (isset($payload['x-ably-clientId']) && $payload['x-ably-clientId'] == $clientId) { + return true; + } + + // If the clientId does not match, return false + return false; + } } diff --git a/tests/AblyBroadcasterTest.php b/tests/AblyBroadcasterTest.php index b06d403..45641f6 100644 --- a/tests/AblyBroadcasterTest.php +++ b/tests/AblyBroadcasterTest.php @@ -184,7 +184,8 @@ public function testShouldHaveUpgradedCapabilitiesForValidToken() $token = $this->broadcaster->getSignedToken('private:channel3', $token, 'user98', $this->guardedChannelCapability); $parsedToken = Utils::parseJwt($token); $payload = $parsedToken['payload']; - $expectedCapability = '{"public:*":["subscribe","history","channel-metadata"],"private:channel":["*"],"private:channel2":["*"],"private:channel3":["*"]}'; + // Since this is a different user, the capabilities from previous token will be reset and only returned for given channel + $expectedCapability = '{"public:*":["subscribe","history","channel-metadata"],"private:channel3":["*"]}'; self::assertEquals('user98', $payload['x-ably-clientId']); self::assertEquals($expectedCapability, $payload['x-ably-capability']); self::assertEquals($iat, $payload['iat']);