Search code examples
phpauthenticationcakephpjwtcakephp-3.x

How to use CakePHP3 "Authentication" Plugin with JWT


I have installed CakePhp 3.8 and i need use JWT authentication.

I have tryed installing and configuring CakePHP/Authentication (https://book.cakephp.org/authentication/1.1/en/index.html) but can not configure this.

My configuration:

  • PHP 7.2.19

  • MySQL 5.7.27

  • Apache 2.4.29

  • CakePHP 3.8

  • Authentication Plugin 1.1

  • firebase/php-jwt

I followed the guide configurations, and have add at AppController.php

// /src/Controller/Appcontroller.php
 public function initialize()
    {
        parent::initialize();
        $this->loadComponent('Authentication.Authentication', [
            'logoutRedirect' => '/administrators/login'  // Default is false
        ]);
....

In Application.php

// /src/application.php
class Application extends BaseApplication implements AuthenticationServiceProviderInterface

....

public function getAuthenticationService(ServerRequestInterface $request, ResponseInterface $response)
    {
        $service = new AuthenticationService();
        $service->loadIdentifier('Authentication.JwtSubject');
        $service->loadAuthenticator('Authentication.Jwt', [
            'returnPayload' => false
        ]);
        return $service;
    }

....

public function middleware($middlewareQueue)
    {
....

        // Add the authentication middleware
        $authentication = new AuthenticationMiddleware($this);

        // Add the middleware to the middleware queue
        $middlewareQueue->add($authentication);

        return $middlewareQueue;
    }

How i can login for first time and retrive JWT token?

-------------------EDIT-------------------

Thankyou, your solutions workly perfectly.

But now i have CORS problem with Angular FE GET request, befor GET this try one OPTIONS request whit CORS error.

I have this CORS policy in my AppController

        // Accepted all CORS
        $this->response = $this->response->cors($this->request)
            ->allowOrigin(['*'])
            ->allowMethods(['GET','POST','PUT','DELETE','OPTIONS','PATCH']) // edit this with more method
            ->allowHeaders(['X-CSRF-Token']) //csrf protection for cors
            ->allowCredentials()
            ->exposeHeaders(['Link'])
            ->maxAge(60)
            ->build();

Solution

  • You'd have to handle that on your own, ie create an endpoint that handles login requests, and upon successful authentication creates a JWT token containing the required identifier.

    For username/password authentication for example you can use the Form authenticator and the Password identifier:

    $service->loadIdentifier('Authentication.Password');
    $service->loadIdentifier('Authentication.JwtSubject');
    
    $service->loadAuthenticator('Authentication.Form', [
        'loginUrl' => '/users/login'
    ]);
    $service->loadAuthenticator('Authentication.Jwt', [
        'returnPayload' => false
    ]);
    

    With that example in UsersController create a login() action like this (that's just a very basic, hopefully self-explanatory example), check the authentication status, if valid generate a token, if invalid generate an error:

    public function login()
    {
        if ($this->Authentication->getResult()->isValid()) {
            $userId = $this->Authentication->getIdentityData('id');
            $token = \Firebase\JWT\JWT::encode(
                ['sub' => $userId],
                \Cake\Utility\Security::getSalt()
            );
    
            $status = 200;
            $response = [
                'token' => $token,
            ];
        } else {
            $status = 403;
            $response = [
                'error' => 'Authentication required',
            ];
        }
    
        return $this
            ->getResponse()
            ->withStatus($status)
            ->withType('json')
            ->withStringBody(json_encode($response));
    }
    

    It probably wouldn't hurt if the cookbook would have a complete example for token authentication.

    See also