ニュース・ブログ

ニュース・ブログ一覧PHPの記事情報Cakephp API using JWT authentication

Cakephp API using JWT authentication

-Let’s try to create an API endpoint to save a category using POST request. Where the case is to save the category users should have a login user. That means at first the user has to login to send a post request to create a category. For this scenario we can draw 2 diagrams.


Diagram 1:

 

JWT (JSON web token) has 3 parts

 

  • HEADER 

   –It will describe algorithm and token types.

  • PAYLOAD

  –Which is data, and it will be set by you. You also mention token expiry here.

  • SIGNATURE

–This signature will depend on your algorithm.

 

After finished diagram 1 step the 2nd 2nd step will be like below

Diagram 2:

 

So you can send API requests to the server until your token expires. Let’s do this both parts in cakephp end. 

 

Requirements: Requirements: 

   –To generate JWT (JSON web token) we will use a package called firebase / php- jwt
–Link
: https://github.com/firebase/php-jwt
   –We will use cakephp version 4
–Databases 
can be mysql or postgres depending on you.
   –We will also use cakephp Authentication plugin 

             –Link: https://book.cakephp.org/authentication/2/en/index.html


Example we have a simple database where has two tables called users and categories

 

Users Table has below fields 
id, email, password (VARCHAR 100), created, modified 

 

Categories Table has below fields 

id, title, created, modified.

 

STEP 1: 

I think you know about cakephp bake commands, do you? 

Example: Example: 

bin / cake bake all users

 

bin / cake bake all categories

 

STEP 2: Create routes in routes.php file 

$ routes-> scope (‘/ api’, function (RouteBuilder $ routes) {

       $ routes-> setExtensions ([‘json’]);

 

       $ routes-> post (

           ‘/ user / create’,

           [‘controller’ => Users,’action’ => add,’prefix’ =>’Api’]

       );

 

       $ routes-> post (

           ‘/ user / login’,

           [‘controller’ => Users,’action’ =>’login’,’prefix’ =>’Api’]

       );

      

       $ routes-> post (

           ‘/ add-categories’,

           [‘controller’ => Categories,’action’ => add,’prefix’ =>’Api’]

       );

});

}

 

STEP 3: After creating the basic MVC code then lets install the cakephp authentication plugin and also firebase / php-jwt.

composer require “cakephp / authentication: ^ 2.0”

composer require firebase / php-jwt

 

STEP 4:

Here to generate JWT we will use the RS256 algorithm. So we require 2 keys, 1 is public and another is private key. To generate both keys follow below commands. 

 

#generate private key

openssl genrsa –out config / jwt . key 1024 _

#generate public key

openssl rsa –in config / jwt . key –outform PEM –pubout –out config / jwt .pem _ _ _ _ _

Check you key has generated in location config / jwt.key and config / jwt.pem 

 

Jwt.key = Private key 

Jwt.pem = Public key 

 

STEP 5: 

 

Implement authentication plugin in your application , you can follow below tutorial link

https://book.cakephp.org/4/en/tutorials-and-examples/cms/authentication.html

Let’s describe shortly which you have done in authentication plugin implementation. 

 

In Entity/User.php you have used below function to create your password hash

<?php 

 

use Authentication\PasswordHasher\DefaultPasswordHasher;

class User extends Entity 

{
  …
  protected function _setPassword(string $password) : ?string

   {

       if (strlen($password) > 0) {

           return (new DefaultPasswordHasher())->hash($password);

       }

   }

 …

}

?>

 

In you middleware you have added AuthenticationMiddleware in middleware() method like below

 

->add(new AuthenticationMiddleware($this))

 

You also wrote a method called getAuthenticationService() in Application.php file and also you have created a method in the login() method in the controller.

 

STEP 6: 


To create a JWT token we will make a little change in the login() method which we have written UsersController.php after following the mentioned tutorial above.

Now to generate JWT we will change our login() method in UsersController like below

 


   public function login()

   {

       $result = $this->Authentication->getResult();

       if ($result->isValid()) {

           $privateKey = file_get_contents(CONFIG . ‘/jwt.key’);  //access private key 

           $user = $result->getData();

           $payload = [

               ‘iss’ => ‘miles’,

               ‘sub’ => $user->id,

               ‘exp’ => strtotime(“+1 week”),    // given 1 week token expiry 

           ];

           $json = [

               ‘token’ => JWT::encode($payload, $privateKey, ‘RS256’),   //used RS256 algo

           ];

       } else {

           $this->response = $this->response->withStatus(401);

           $json = [];

       }

       $this->set(compact(‘json’));

       $this->viewBuilder()->setOption(‘serialize’, ‘json’)

}

 

Don’t forget to use Firebase\JWT\JWT; after your namespace. 

 

<?php 

namespace App\Controller;

use Cake\Event\EventInterface;

use Cake\Utility\Security;

use Firebase\JWT\JWT;

 

?>

 

Lets give permission to access login action in beforefilter method 

 

public function beforeFilter(EventInterface $event)

 {

       parent::beforeFilter($event);

 

       $this->Authentication->allowUnauthenticated([‘login’,’add’]);

 }

 

To access in your API endpoint, you can change your middleware getAuthenticationService() method like below



public function getAuthenticationService(ServerRequestInterface $request): AuthenticationServiceInterface

   {

       $service = new AuthenticationService();

 

       $fields = [

           IdentifierInterface::CREDENTIAL_USERNAME => ‘email’,

           IdentifierInterface::CREDENTIAL_PASSWORD => ‘password’

       ];

 

       $service->loadAuthenticator(‘Authentication.Form’, [

           ‘fields’ => $fields,

       ]);

 

       // https://book.cakephp.org/authentication/2/en/authenticators.html#jwt

       $service->loadIdentifier(‘Authentication.JwtSubject’);

       // Load the authenticators.

       $service->loadAuthenticator(‘Authentication.Jwt’, [

           ‘secretKey’ => file_get_contents(CONFIG . ‘/jwt.pem’),

           ‘algorithm’ => ‘RS256’,

           ‘returnPayload’ => false

       ]);

 

       $service->loadIdentifier(‘Authentication.Password’, [

           ‘returnPayload’ => false,

           ‘fields’ => $fields,

       ]);

 

       return $service;

   }

 

 

Now try in postman like below after create an user

In postman set your token in Bearer like below SC

Then set body like below SC then send request


That’s it !

Written By: Alimon Karim Pito