request('POST', '/api/token/refresh', [ 'json' => [], 'headers' => [ 'Host' => 'localhost', ], ]); // THEN: Returns 401 Unauthorized self::assertResponseStatusCodeSame(401); } #[Test] public function logoutEndpointIsAccessibleWithoutToken(): void { // GIVEN: No authentication $client = static::createClient(); // WHEN: Calling logout endpoint $response = $client->request('POST', '/api/token/logout', [ 'json' => [], 'headers' => [ 'Host' => 'localhost', ], ]); // THEN: Returns 200 OK (idempotent - no token to invalidate) self::assertResponseIsSuccessful(); } #[Test] public function logoutEndpointClearsCookies(): void { // GIVEN: A client $client = static::createClient(); // WHEN: Calling logout $response = $client->request('POST', '/api/token/logout', [ 'headers' => [ 'Host' => 'localhost', 'Cookie' => 'refresh_token=some-token-value', ], ]); // THEN: Response sets expired cookies $setCookieHeaders = $response->getHeaders(false)['set-cookie'] ?? []; $this->assertNotEmpty($setCookieHeaders); $hasClearedCookie = false; foreach ($setCookieHeaders as $cookie) { if (str_contains($cookie, 'refresh_token=') && str_contains($cookie, 'expires=')) { $hasClearedCookie = true; break; } } $this->assertTrue($hasClearedCookie, 'Should set expired refresh_token cookie'); } #[Test] public function refreshEndpointWithInvalidTokenReturns401(): void { // GIVEN: An invalid/malformed token in cookie $client = static::createClient(); // WHEN: Calling refresh with invalid cookie $response = $client->request('POST', '/api/token/refresh', [ 'json' => [], 'headers' => [ 'Host' => 'localhost', 'Cookie' => 'refresh_token=invalid-token-format', ], ]); // THEN: Returns 401 Unauthorized self::assertResponseStatusCodeSame(401); } }