In the article on [CakePHP 4: How to Create a Login Function]. I have guided on how to create a login function using a web interface by combining Session and Cookie. In this article, I will guide you on how to create a token-based login and authentication function.
The steps to install the Authentication 2.0 plugin, create a controller, model, etc., have been guided in the article [CakePHP 4: How to Create a Login Function]. If you haven't read it, you can refer to the article at https://isb-vietnam.com.vn/cakephp-4-how-to-create-a-login-function/.
1, Understand Token-Based Authentication.
To understand how the login function works, you can see the diagram below:
In a token-based application, The server will create a JWT and send the JWT back to the client when the user logs in. In subsequent requests, the client will send requests to the server with the JWT included in the header. The server will check if the JWT is valid to respond.
2, Implement JWT in CakePHP 4.
By default the JwtAuthenticator uses HS256 symmetric key algorithm and uses the value of Cake\Utility\Security::salt() as encryption key. For enhanced security one can instead use the RS256 asymmetric key algorithm.
Create encryption key.
# 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
The jwt.key file is the private key and should be kept safe. The jwt.pem file is the public key. This file should be used when you need to verify tokens created by external applications, eg: mobile apps.
Implement.
In src/Application.php, change the source code to identify the user based on the subject of the token by using JwtSubject identifier, and configures the Authenticator to use public key for token verification.
public function getAuthenticationService(ServerRequestInterface $request): AuthenticationServiceInterface
{
$service = new AuthenticationService([
'unauthenticatedRedirect' => Router::url('/login'),
'queryParam' => 'redirect',
]);
//…
$service->loadIdentifier('Authentication.JwtSubject');
$service->loadAuthenticator('Authentication.Jwt', [
'header' => 'Authorization',
'secretKey' => file_get_contents(CONFIG . 'jwt.pem'),
'algorithm' => 'RS256',
'returnPayload' => false
]);
return $service;
}
In UsersController.php, create a login function as below.
public function login()
{
if ($this->request->is('post')) {
$result = $this->Authentication->getResult();
if ($result->isValid()) {
$privateKey = file_get_contents(CONFIG . 'jwt.key');
$user = $result->getData();
$payload = [
'iss' => 'myapp',
'sub' => $user->id,
'exp' => time() + 3600, // 1 hour
];
$json = [
'token' => JWT::encode($payload, $privateKey, 'RS256'),
];
} else {
$this->response = $this->response->withStatus(401);
$json = [
"message" => __('The Username or Password is Incorrect')
];
}
$this->RequestHandler->renderAs($this, 'json');
$this->response->withType('application/json');
$this->set(['json' => $json]);
$this->viewBuilder()->setOption('serialize', 'json');
} else {
throw new NotFoundException();
}
}
Testing.
We create APIs to verify the token-based login function with the rules as shown in the table below:
Title | endpoints | remark |
Retrieve All Articles (GET) | /api/articles.json | Can only be used by all users. Users can see information about articles and the total number of likes for each article. |
Create an Article (POST) | /api/articles.json | Can only be used by authenticated users. |
Perform login testing using Postman. In case of a successful login, a token will be returned.
Call API Retrieve All Articles (GET), Can only be used by all users.
Call API Create an Article (POST), can only be used by authenticated users.
The result is returned successfully with the token attached in the header.
The result is returned unsuccessfully because the token is not attached in the header.
You can find the complete source code at: https://github.com/ivc-phampbt/cakephp-authentication
Conclusion
In this article, I introduced a new login method called Token-Based Authentication and how web applications authenticate using tokens. I hope this article provides knowledge to help you build token-based login features more easily.