I am attempting to test my Laravel 4 REST API using Codeception, but when I try to send through my Authorization header (using the $I->amBearerAuthenticated() function of the REST module) it is not making it through to the eventual request.
From what I can see, the Symfony2 BrowserKit module modifies any headers added into the HTTP_XXX_XXX format, so the header being sent seems to be HTTP_AUTHORIZATION - when I output the received headers in my application, however, neither Authorization nor HTTP_AUTHORIZATION are present.
If it helps, here is my Codeception test:
public function loginAndHitProtectedPage(ApiTester $I)
{
$I->wantTo('login and successfully get to a protected page');
$I->sendPOST('/auth/login', ['username' => 'user1', 'password' => 'pass']);
$I->seeResponseIsJson();
$token = $I->grabDataFromJsonResponse('token');
$I->amBearerAuthenticated($token);
$I->sendGET('/runs');
$I->seeResponseCodeIs(200);
$I->seeResponseIsJson();
$I->dontSeeResponseContains('error');
}
Headers sent according to BrowserKit (output of $this->client->getInternalRequest()->getServer()
in the REST module) :
HTTP_HOST : localhost
HTTP_USER_AGENT : Symfony2 BrowserKit
HTTP_AUTHORIZATION : Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC9sb2NhbGhvc3RcL2F1dGhcL2xvZ2luIiwic3ViIjoxLCJpYXQiOjE0MjE3ODY0NDEsImV4cCI6MTQyMTg3Mjg0MX0.XxxxZMe8gwF9GS8CdKsh5coNQer1c6G6prK05QJEmDQ
HTTP_REFERER : http://localhost/auth/login
HTTPS : false
Headers received according to PHP:
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Accept-Language: en-us,en;q=0.5
Content-Type: application/x-www-form-urlencoded
Host: localhost
Referer: http://localhost/auth/login
User-Agent: Symfony2 BrowserKit
The token is received correctly, but my API (correctly) returns a 401 on the GET request because it's not receiving the token.
Any help would be greatly appreciated!
I'm using Laravel 5 (no big diff from L4) and REST modules. This is the way I'm doing it right now:
protected $token;
public function _before(ApiTester $I)
{
$user = TestDummy(...);
$I->sendPOST('/v1/auth/login', [
'email' => $user->email,
'password' => $user->password
]);
$this->token = $I->grabDataFromResponseByJsonPath('$.token');
}
Then in my tests:
// Do stuff ...
$I->amBearerAuthenticated($this->token[0]);
// Do more stuff ...
I'm sure there are better ways to do this, but until I find a better one this is working.
There is a workaround. Using $I->amHttpAuthenticated("test", "test")
makes the Authorization:
header permanent. Not sure if this is bug or feature. Instead build the Authorization: Basic
header manually so you can delete it before setting the Authorization: Bearer
header.
$I = new ApiTester($scenario);
$I->wantTo("fetch token and use it as bearer");
/* This does not work. */
/* $I->amHttpAuthenticated("test", "test"); */
/* Instead use this. */
$I->setHeader("Authorization", "Basic dGVzdDp0ZXN0");
$I->haveHttpHeader("Content-Type", "application/json");
$I->sendPOST("token", ["read", "write"]);
$I->seeResponseCodeIs(201);
$I->seeResponseIsJson();
$I->seeResponseContainsJson(["status" => "ok"]);
$token = $I->grabDataFromJsonResponse("token");
/* Delete the basic auth header before adding bearer. */
$I->deleteHeader("Authorization");
$I->amBearerAuthenticated($token);
After some digging into the guts of Laravel and Codeception, I discovered that the problem was with the fact that I was using the Laravel4 module at the same time as the REST module. I hadn't realised that using Laravel4 for HTTP requests actually just simulates the request to the route within the same session, and thus my JWTAuth object was only being resolved out of the IOC container on the first REST call in any particular test. This meant that when making subsequent calls, the request (including headers) from the first call was being retained and thus the Authorization header (which at that point was being passed through with the Request object correctly) was not being seen.
I was really only using the Laravel4 module to set my environment to 'testing' and to ensure that my filters were running in that environment, so I will now just have to figure out a different way to set that without having to modify my bootstrap/start.php everytime I want to run my tests.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With