Buy

We already added a denyAccessUnlessGranted() line to ProgrammerController::newAction(). That means this endpoint is broken: we don't have an API authentication system hooked up yet.

Open up ProgrammerControllerTest() and find testPOST(): the test for this endpoint:

256 lines tests/AppBundle/Controller/Api/ProgrammerControllerTest.php
... lines 1 - 6
class ProgrammerControllerTest extends ApiTestCase
{
... lines 9 - 15
public function testPOST()
{
... lines 18 - 34
}
... lines 36 - 254
}

Rename this to testPOSTProgrammerWorks() - this will make its name unique enough that we can run it alone:

262 lines tests/AppBundle/Controller/Api/ProgrammerControllerTest.php
... lines 1 - 6
class ProgrammerControllerTest extends ApiTestCase
{
... lines 9 - 15
public function testPOSTProgrammerWorks()
{
... lines 18 - 40
}
... lines 42 - 260
}

Copy that name and run it:

./vendor/bin/phpunit --filter testPOSTProgrammerWorks

Instead of the 201, we get a 200 status code after being redirected to /login. I know we don't have our security system hooked up yet, but pretend that it is hooked up and working nicely. How can we update the test to send a token?

Sending a Token in the Test

Well, first, we'll need to create a valid token. Do that the same way we just did in the controller: $token = $this->getService() - which is just a shortcut we made to fetch a service from the container - and grab the lexik_jwt_authentication.encoder service. Finally, call encode() and pass it ['username' => 'weaverryan']:

262 lines tests/AppBundle/Controller/Api/ProgrammerControllerTest.php
... lines 1 - 6
class ProgrammerControllerTest extends ApiTestCase
{
... lines 9 - 15
public function testPOSTProgrammerWorks()
{
$data = array(
'nickname' => 'ObjectOrienter',
'avatarNumber' => 5,
'tagLine' => 'a test dev!'
);
$token = $this->getService('lexik_jwt_authentication.encoder')
->encode(['username' => 'weaverryan']);
... lines 26 - 40
}
... lines 42 - 260
}

And we have a token! Now, how do we send it to the server? Well, it's our API, so we can do whatever the heck we want! We can set it as a query string or attach it on a header. The most common way is to set it on a header called Authorization. Add a headers key to the Guzzle call with one header called Authorization. Set its value to the word Bearer, a space, and then the $token.:

262 lines tests/AppBundle/Controller/Api/ProgrammerControllerTest.php
... lines 1 - 6
class ProgrammerControllerTest extends ApiTestCase
{
... lines 9 - 15
public function testPOSTProgrammerWorks()
{
... lines 18 - 26
// 1) Create a programmer resource
$response = $this->client->post('/api/programmers', [
'body' => json_encode($data),
'headers' => [
'Authorization' => 'Bearer '.$token
]
]);
... lines 34 - 40
}
... lines 42 - 260
}

Weird as it might look, this is a really standard way to send a token to an API. If we re-run the test now, it of course still fails. But we're finally ready to create an authentication system that looks for this token and authenticates our user.

Leave a comment!

  • 2016-06-09 Vlad

    Thank you! That was it. I needed to add the firewall configs. I'll check the entry point chapter. Thanks again.

  • 2016-06-08 weaverryan

    Just saw this message :). What behavior *are* you getting? Ultimately, the /login redirection is caused by the "form_login" system in the firewall. It's possible that you don't have that (or have some other behavior). Check out the entry point chapter, but let me know if you have questions - the "entry point" idea can be tricky.

  • 2016-06-08 weaverryan

    Hi Vlad!

    That's explained a few chapters from here - it's caused by what's called an "entry point": https://knpuniversity.com/scre...

    Hope that helps!

  • 2016-06-08 Vlad

    I'm following this tutorial and working on parallel project and for some reason I don't get the /login redirection. What am I missing?

  • 2016-06-08 Vlad

    Where is the /login redirection covered? How does it happen?
    Thanks