Real-time communication using Socket.io with Azure AD authentication
The Portal Self-Service Backend uses Socket.io to provide real-time bidirectional communication between the server and clients, with integrated Azure AD JWT authentication.
The server uses jwks-rsa to fetch and verify Azure AD public keys:
// From socket.js:10-25import jwksClient from 'jwks-rsa';// Client to fetch public keys from Microsoft Entra IDconst client = jwksClient({ jwksUri: `${process.env.AZURE_ISSUER_BASE_URL}/discovery/v2.0/keys`});// Helper function to get signing key for JWT verificationfunction getKey(header, callback) { client.getSigningKey(header.kid, function(err, key) { if (err) { callback(err, null); } else { const signingKey = key.publicKey || key.rsaPublicKey; callback(null, signingKey); } });}
Every Socket.io connection is authenticated before being established:
// From socket.js:36-74io.use((socket, next) => { // Frontend must pass token: // const socket = io(url, { auth: { token: 'jwt_token_here' } }); const token = socket.handshake.auth.token; if (!token) { return next(new Error('Autenticación requerida: No se proporcionó token.')); } // Verify token against Microsoft jwt.verify(token, getKey, { audience: process.env.AZURE_AUDIENCE, issuer: process.env.AZURE_ISSUER_BASE_URL }, async (err, decoded) => { if (err) { console.error("Socket Auth Error:", err.message); return next(new Error('Autenticación fallida: Token de Azure inválido.')); } // Token is 100% valid and signed by Microsoft try { // Look up user in local database using Azure email const userEmail = decoded.upn || decoded.preferred_username; const empleado = await Empleado.findOne({ where: { correo: userEmail } }); if (!empleado) { return next(new Error('Usuario no encontrado en el sistema local.')); } // Store internal database ID in socket for notifications socket.userId = empleado.id_empleado; next(); } catch (dbError) { console.error("Error buscando usuario en DB para Socket:", dbError); return next(new Error('Error interno de servidor durante la autenticación.')); } });});
Authentication failures prevent the WebSocket connection from being established. Ensure the client passes a valid Azure AD JWT token.
The notification system uses rooms to deliver messages to specific users:
// From socket.js:91-97notificationEmitter.on(EVENTOS_INTERNOS.NOTIFICACION_CREADA, (notificacionData) => { const roomDestinatario = `room_${notificacionData.id_usuario}`; io.to(roomDestinatario).emit('nueva_notificacion', notificacionData); console.log(`[Socket] Notificación enviada a la sala ${roomDestinatario}`);});