My project is using a modified implementation of Laravel Passport for authentication.
I have a route, /auth/login, which I use for authentication. POST is for logging in, PUT is for refreshing tokens, and DELETE is for logging out. Here's the update method of my controller, which is mapped to PUT /auth/login. It is supposed to find the refresh token in the cookie and use it in the performProxyRequest method. However, when I add the cookie to a request in one of my feature tests, $token is always null.
/**
* Refresh an access token.
*
* @param Request $request
* @return Response
* @throws JsonException
*/
public function update(Request $request): Response
{
$token = Cookie::get(Passport::cookie());
if (is_null($token)) {
return response([
'message' => 'Refresh token not found.',
], SymfonyResponse::HTTP_UNAUTHORIZED);
}
$request->request->add([
'refresh_token' => $token
]);
return $this->performProxyRequest($request, 'refresh_token');
}
Here is my current feature test with the different attempts I've tried to add the cookie in.
#[Test]
public function an_update_request_is_successful(): void
{
// Login first, the cookie will be in the response.
/** @var Cookie $cookie */
$cookie = $this->postJson(route('auth.login'), $this->credentials)
->getCookie(Passport::cookie());
// Attempt 1: standard approach, using `withCookie`.
$response = $this->withCookie($cookie->getName(), $cookie->getValue())
->putJson(route('auth.refresh-tokens'));
// Attempt 2: same as the first attempt, but without the `route` helper.
//$response = $this->withCookie($cookie->getName(), $cookie->getValue())
// ->putJson('/auth/login');
// Attempt 3: standard approach, using `withUnencryptedCookie`.
//$response = $this->withUnencryptedCookie($cookie->getName(), $cookie->getValue())
// ->putJson(route('auth.refresh-tokens'));
// Attempt 4: a more manual approach using `call`
//$response = $this->call(
// method: 'PUT',
// uri: route('auth.login'),
// cookies: [
// $cookie->getName() => $cookie->getValue(),
// ],
//);
// Attempt 5: manually create a request and dispatch it.
//$request = Request::create(
// uri: route('auth.login'),
// method: 'PUT',
// cookies: [
// $cookie->getName() => $cookie->getValue(),
// ],
//);
//$response = Route::dispatch($request);
$response->assertOk()
->assertJson(static function (AssertableJson $json): void {
$json->where('token_type', 'Bearer')
->where('expires_in', 900)
->has('access_token')
->has('refresh_token');
});
/** @var Cookie $cookie */
$cookie = $response->getCookie(Passport::cookie());
$this->assertSame($response->json('refresh_token'), $cookie->getValue());
$this->assertTrue($cookie->isHttpOnly());
$this->assertTrue($cookie->isSecure());
}
No matter what I try, the $token is always null when I run my feature test. I've tried putting break points to insepct the request, dding it, and a few other things. But there cookie is always missing from the request.
I've check the middleware for the request, it's only throttle:login and auth:api, so I don't think there's anything weird going on there.
I've tested this flow using plain cURL requests, the PhpStorm HTTP client, and in my local dev with my frontend application. In all of those cases, using the cookie works. It just doesn't when I'm writing the feature test.
So, I'm not sure what else I can do to get this feature test working.
My Laravel version is 11.0, Passport is 12.0.
Cookieclass, this is why it is important to stick to documentation and do what they recommend or show in there, as they always use$request->cookie, neverCookie::. I used Laravel for 8+ years and never usedCookie::and didn't know it existed at all... I could not find anyCookie::in their docs