This article is part of the CakeDC Advent Calendar 2024 (December 5th 2024)
The use of JWT in communication is vital for modern applications because of its ability to ensure secure authentication and authorization. As applications shift toward distributed architectures, such as microservices or client-server models, JWT becomes an essential tool for securely transmitting sensitive data.
Advantages
- JWT is ideal for authentication, as it can include user information and access levels. Once authenticated, the client can make multiple requests without re-authenticating, optimizing performance.
- JWT includes an expiration time (exp), which mitigates the risk of compromised tokens and ensures expired tokens cannot be reused.
- JWT is an open standard, and widely supported, which enables seamless integration between different systems and services, even if they use different programming languages.
Cases of use
- After login, a JWT containing user data is sent to the client, allowing them to access protected resources.
- Allows services to validate requests independently, without relying on a central authentication server.
- JWT ensures that data exchanged between APIs is not altered, providing mutual trust.
1.- Add with composer the library https://github.com/lcobucci/jwt
composer require "lcobucci/jwt"
2.- Create the logic to generate the token with the secret phrase
src/Controller/PagesController.php
use Lcobucci\JWT\Configuration;
use Lcobucci\JWT\Signer\Hmac\Sha256;
use Lcobucci\JWT\Signer\Key;
class PagesController extends AppController
{
public function generateJwt()
{
$configuration = Configuration::forSymmetricSigner(
new Sha256(),
Key\InMemory::plainText('EBB86CEF-63B0-411E-BA99-55F68E39049C1732552248')
);
$now = FrozenTime::now();
$token = $configuration->builder()
->issuedBy('https://advent.ddev.site')
->permittedFor('https://advent.ddev.site/')
->identifiedBy('4f1g23a12aa')
->issuedAt($now)
->expiresAt($now->modify('+1 hour'))
->withClaim('uid', 'Generated JWT in CakePHP and decoded on a node app')
->getToken($configuration->signer(), $configuration->signingKey())
->toString();
$this->set('token', $token);
}
3.- In the view of this function load socket.io and connect to your server and port.
templates/Pages/generate_jwt.php
<div id="message"></div> <script src="https://cdn.socket.io/4.8.1/socket.io.min.js"></script> <script type="module"> const socket = io('https://advent2024.ddev.site:8182/', { auth: { token: '<?= $token; ?>' } }); socket.on('welcome', (message) => { document.getElementById('message').innerHTML = message; console.log('Connnected!!!' + message) }); socket.on('connect_error', (err) => { document.getElementById('message').innerHTML = 'Error connecting to the server'; }); </script>
4.- Create the node server, for example in: node/app.js
You can check the authentication in the function by using jsonwebtoken verify for the token received, and the secret JWT_SECRET, which is the same as the one used when the token was generated.
import express from 'express';
import { createServer } from 'http';
import jsonwebtoken from 'jsonwebtoken';
import { Server } from 'socket.io';
const { sign, decode, verify } = jsonwebtoken;
let app = express();
const httpServer = createServer(app);
const io = new Server(httpServer, { cors: { origin: '*' } });
// jwt secret
const JWT_SECRET = 'EBB86CEF-63B0-411E-BA99-55F68E39049C1732552248';
//authentication middleware
io.use(async(socket, next) => {
// fetch token from handshake auth sent by FE
const token = socket.handshake.auth.token;
try {
// verify jwt token and get user data and save the user data into socket object, to be used further
socket.decoded = await jsonwebtoken.verify(token, JWT_SECRET);
console.log(socket.decoded);
next();
} catch (e) {
// if token is invalid, close connection
console.log('info', `Not Valid authentication! ${e.message} disconnected!`);
return next(new Error(e.message));
}
});
io.on('connection',function (socket) {
console.log('info',`A client with socket id ${socket.id} connected!`);
// Emitir un mensaje de bienvenida al cliente
socket.emit('welcome', 'Welcome to Node server!!!');
});
httpServer.listen(8180);
console.log('listen...');
5.- Launch the Node server
then execute your node server. In the below image, you see printed the valid token decoded.
node node/app.js
Connection on client side
Conclusion
Using JWT is crucial for modern systems that require secure, efficient, and scalable communication. Its ability to encapsulate signed and verifiable information, along with its lightweight design and open standard, makes it a powerful tool for distributed architectures and applications reliant on robust authentication and authorization. Implementing JWT in an application ensures an optimal balance between security and performance.
You can see a complete example in https://github.com/ACampanario/advent2024
This article is part of the CakeDC Advent Calendar 2024 (December 5th 2024)