9

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!

1
  • I got PHPStorm debugging working for my tests and I've made some progress on pinpointing this issue, though I'm still a bit stuck. It looks like the JWTAuth module I'm using for Authorization is part of the issue - because I'm making two REST calls in the same test, the JWTAuth module only seems to get initialized for the first one, and as part of the initialization the request is stored. Then when the second call is made, the headers from the first request are used and thus the Authorization header is not present. If I hardcode the token and just make the second GET, it works. Continuing... Commented Jan 21, 2015 at 16:09

3 Answers 3

5

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.

Sign up to request clarification or add additional context in comments.

2 Comments

so you are calling $I->amBearerAuthenticated($this->token[0]); in all the functions ? Is there anyway that we can do it once in the class and utilize it ?
You can extract it to a trair or create a base class then other extend that
5

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);

4 Comments

I don't think there is deleteHeader method.
but this works too, instead of using amHttpAuthenticated just use haveHttpHeader two times.
Login through $I->haveHttpHeader("Authorization", "Basic $token"); seems to work, the header is really sended.
This works like a charm for me, just a little hint to convert the credentials to base64 directly from the code : $I->setHeader("Authorization", "Basic ".base64_encode($username . ':' . $password));
2

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.