diff --git a/Authentication/JWT.php b/Authentication/JWT.php index 905920a7..5f319e39 100644 --- a/Authentication/JWT.php +++ b/Authentication/JWT.php @@ -15,6 +15,12 @@ */ class JWT { + + /** + * When cheking nbf, iat or expiration times, we want to provide some extra leeway time to account for clock skew. + */ + const LEEWAYTIME = 60; + public static $supported_algs = array( 'HS256' => array('hash_hmac', 'SHA256'), 'HS512' => array('hash_hmac', 'SHA512'), @@ -80,7 +86,7 @@ public static function decode($jwt, $key = null, $allowed_algs = array()) // Check if the nbf if it is defined. This is the time that the // token can actually be used. If it's not yet that time, abort. - if (isset($payload->nbf) && $payload->nbf > time()) { + if (isset($payload->nbf) && $payload->nbf > (time() + self::LEEWAYTIME)) { throw new BeforeValidException( 'Cannot handle token prior to ' . date(DateTime::ISO8601, $payload->nbf) ); @@ -89,14 +95,14 @@ public static function decode($jwt, $key = null, $allowed_algs = array()) // Check that this token has been created before 'now'. This prevents // using tokens that have been created for later use (and haven't // correctly used the nbf claim). - if (isset($payload->iat) && $payload->iat > time()) { + if (isset($payload->iat) && $payload->iat > (time() + self::LEEWAYTIME)) { throw new BeforeValidException( 'Cannot handle token prior to ' . date(DateTime::ISO8601, $payload->iat) ); } // Check if this token has expired. - if (isset($payload->exp) && time() >= $payload->exp) { + if (isset($payload->exp) && (time() - self::LEEWAYTIME) >= $payload->exp) { throw new ExpiredException('Expired token'); } } diff --git a/tests/JWTTest.php b/tests/JWTTest.php index c48427de..b685ce49 100644 --- a/tests/JWTTest.php +++ b/tests/JWTTest.php @@ -38,9 +38,11 @@ public function testMalformedJsonThrowsException() public function testExpiredToken() { $this->setExpectedException('ExpiredException'); + $timeInPast = time() - JWT::LEEWAYTIME - 20; $payload = array( "message" => "abc", - "exp" => time() - 20); // time in the past + "exp" => $timeInPast // time in the past + ); $encoded = JWT::encode($payload, 'my_key'); JWT::decode($encoded, 'my_key', array('HS256')); } @@ -48,9 +50,11 @@ public function testExpiredToken() public function testBeforeValidTokenWithNbf() { $this->setExpectedException('BeforeValidException'); + $timeInFuture = time() + JWT::LEEWAYTIME + 20; $payload = array( "message" => "abc", - "nbf" => time() + 20); // time in the future + "nbf" => $timeInFuture // time in the future + ); $encoded = JWT::encode($payload, 'my_key'); JWT::decode($encoded, 'my_key', array('HS256')); } @@ -58,9 +62,11 @@ public function testBeforeValidTokenWithNbf() public function testBeforeValidTokenWithIat() { $this->setExpectedException('BeforeValidException'); + $timeInFuture = time() + JWT::LEEWAYTIME + 20; $payload = array( "message" => "abc", - "iat" => time() + 20); // time in the future + "iat" => $timeInFuture // time in the future + ); $encoded = JWT::encode($payload, 'my_key'); JWT::decode($encoded, 'my_key', array('HS256')); }