diff --git a/src/Appwrite/Utopia/Response/Model/ResourceToken.php b/src/Appwrite/Utopia/Response/Model/ResourceToken.php index 17d97ab0ca..87ab66ab5d 100644 --- a/src/Appwrite/Utopia/Response/Model/ResourceToken.php +++ b/src/Appwrite/Utopia/Response/Model/ResourceToken.php @@ -63,8 +63,8 @@ class ResourceToken extends Model { $expire = $document->getAttribute('expire'); - // Disable library auto-exp; rely solely on explicit exp in payload when set - $jwt = new JWT(System::getEnv('_APP_OPENSSL_KEY_V1'), 'HS256', 0, 10); + // Use a large but reasonable maxAge to avoid auto-exp when we set explicit exp + $jwt = new JWT(System::getEnv('_APP_OPENSSL_KEY_V1'), 'HS256', 86400 * 365 * 10, 10); // 10 years $payload = [ 'tokenId' => $document->getId(), @@ -77,6 +77,9 @@ class ResourceToken extends Model if ($expire !== null) { $expiryDate = new \DateTime($expire); $payload['exp'] = $expiryDate->getTimestamp(); + } else { + // For infinite expiry, set 'iat' to prevent JWT library from auto-adding 'exp' + $payload['iat'] = time(); } $secret = $jwt->encode($payload); diff --git a/tests/e2e/Services/Tokens/TokensConsoleClientTest.php b/tests/e2e/Services/Tokens/TokensConsoleClientTest.php index 94529f7280..a34555d9cc 100644 --- a/tests/e2e/Services/Tokens/TokensConsoleClientTest.php +++ b/tests/e2e/Services/Tokens/TokensConsoleClientTest.php @@ -106,10 +106,10 @@ class TokensConsoleClientTest extends Scope // Add padding if needed $payloadB64 .= str_repeat('=', (4 - strlen($payloadB64) % 4) % 4); $payload = json_decode(base64_decode($payloadB64), true); - + $this->assertIsArray($payload, 'JWT payload should decode to an array'); $this->assertArrayHasKey('exp', $payload, 'JWT payload should contain exp field'); - + $expectedExp = (new \DateTime($expiry))->getTimestamp(); $this->assertEquals($expectedExp, $payload['exp'], 'JWT exp should match token expiry'); @@ -129,7 +129,7 @@ class TokensConsoleClientTest extends Scope $payloadB64 = str_replace(['-', '_'], ['+', '/'], $payloadB64); $payloadB64 .= str_repeat('=', (4 - strlen($payloadB64) % 4) % 4); $payload = json_decode(base64_decode($payloadB64), true); - + $this->assertArrayNotHasKey('exp', $payload, 'JWT payload should not contain exp field for infinite expiry'); return $data;