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