0

Using the authentication plugin, I'm unable to verify my credentials via json. I can use Form, Jwt and Basic(For testing it works). The error returned is 'FAILURE_CREDENTIALS_INVALID'. Here's the sample code "simplified for brevity"

public function token()
{

    $result = $this->Authentication->getResult();
    if ($result->isValid()) {
        //new jwt token etc
        $message = true;
        $this->log($result->getStatus());

    }else{
        $message = false;
        $this->log($result->getStatus());

    }

    $this->set([
        'message' => $message,

    ]);

    $this->viewBuilder()->setOption('serialize', ['message']);

}

My application class has the method

public function getAuthenticationService(ServerRequestInterface $request) : AuthenticationServiceInterface
{

    $service = new AuthenticationService();

    $service->setConfig([
        'unauthenticatedRedirect' => '/users/login',
        'queryParam' => 'redirect',
    ]);


    $fields = [
        'username' => 'email',
        'password' => 'password'
    ];

    // Load the authenticators, you want session first
    $service->loadAuthenticator('Authentication.Session');
    $service->loadAuthenticator('Authentication.Form', [
        'fields' => $fields,
        'loginUrl' => '/users/login'
    ]);

    //Testing jwt
    $service->loadAuthenticator('Authentication.Jwt', [
        'secretKey' => Security::getSalt()]);

    // Load identifiers
    $service->loadIdentifier('Authentication.Password', compact('fields'));
    $service->loadIdentifier('Authentication.JwtSubject');

    return $service;
}

The app is serving some json well if I pass in the jwt, but somehow I can't figure out how to request a new one, when the old expires. image with sample json data credentials

Here's my middlewareQueue:

//some code

    $middlewareQueue

        ->add(new ErrorHandlerMiddleware(Configure::read('Error')))
        ->add(new AssetMiddleware([
            'cacheTime' => Configure::read('Asset.cacheTime'),
        ]))
        ->add(new RoutingMiddleware($this))
        ->add($csrf)
        ->add(new BodyParserMiddleware())
        ->add(new AuthenticationMiddleware($this));

   //more code

I DO NOT use basic

ndm
  • 59,784
  • 9
  • 71
  • 110
back2back
  • 113
  • 11
  • Are you sending the correct `Content-Type` header? And have you loaded the body parser middleware? – ndm Feb 05 '20 at 21:44
  • Content-Type is application/json. Added BodyParserMiddleware(); I have an api route on routes.php file. Using $this->request->geData('email'); I can log the data which means its POSTed. I've added my middlwareQueue to the answer as well. – back2back Feb 06 '20 at 05:25
  • @ndm Also note there's no BASIC auth on the getAuthenticationService(); – back2back Feb 06 '20 at 05:37
  • Also could it be that I'm in an "Api" subfolder with its own controllers? Maybe the form authenticator is looking for the wrong controller – back2back Feb 06 '20 at 05:53
  • I think I misunderstood what you're trying to do, respectively what you're expecting to happen. You want to authenticate against the form authenticator on the `/api/users/token` endpoint, and retrieve a JWT token in response? Also are you aware that with your setup, such a request (if successful) would try to persist the authenticated user in the session (ie add a session cookie to the response accordingly)? – ndm Feb 06 '20 at 11:15
  • yes. I was looking for a way to get a new token, by submitting the email pwd combo. – back2back Feb 06 '20 at 11:18
  • Hmm, maybe I should exchange the jwt sometime before it expires, Because I was expecting one of the authenticators to give me a result. – back2back Feb 06 '20 at 11:19
  • 1
    The form authenticator could, you'd just need to add the respective path to the `loginUrl` option, currently it only runs on `/users/login`, ie pass an array with all the URL paths you want the form authenticator to run. – ndm Feb 06 '20 at 11:24
  • @ndm yes that solved it. – back2back Feb 06 '20 at 12:05

1 Answers1

2

As mentioned in the comments, if you want to authenticate using the form authenticator on your token retrieval endpoint, then you need to make sure that you include the URL path of that endpoint in the authenticators loginUrl option.

That option accepts an array, so it should be as simple as this:

$service->loadAuthenticator('Authentication.Form', [
    'fields' => $fields,
    'loginUrl' => [
        '/users/login',
        '/api/users/token.json',
    ],
]);

The error that you were receiving was because the form authenticator simply wasn't applied on the token endpoint, and therefore the authentication service would go to the next authenticator, the JWT authenticator, which isn't bound to a specific endpoint, and therefore can run for all endpoints, and the JWT authenticator of course expects a different payload, it looks for a token, and if it can't find it, it will return the error status FAILURE_CREDENTIALS_INVALID.

ndm
  • 59,784
  • 9
  • 71
  • 110