const jwksClient = require('jwks-rsa'); const jwt = require('jsonwebtoken'); const client = jwksClient({ jwksUri: process.env.KEYCLOAK_JWKS_URI || 'http://localhost:8080/realms/scommettiapp/protocol/openid-connect/certs', cache: true, rateLimit: true, jwksRequestsPerMinute: 5, }); function getKey(header, callback) { client.getSigningKey(header.kid, (err, key) => { if (err) return callback(err); callback(null, key.getPublicKey()); }); } module.exports = sequelize => { const { User } = sequelize.models; return (req, res, next) => { const authHeader = req.headers.authorization; if (!authHeader || !authHeader.startsWith('Bearer ')) { return res.status(401).json({ success: false, message: 'Token mancante o non valido' }); } const token = authHeader.slice(7); jwt.verify(token, getKey, { algorithms: ['RS256'] }, async (err, decoded) => { if (err) { return res.status(401).json({ success: false, message: 'Token non valido o scaduto' }); } try { const keycloakId = decoded.sub; const name = decoded.name || `${decoded.given_name || ''} ${decoded.family_name || ''}`.trim() || decoded.preferred_username || 'Utente'; const email = decoded.email || `${keycloakId.slice(0, 8)}@scommetti.app`; const avatarUrl = `https://picsum.photos/seed/${keycloakId.slice(0, 8)}/200/200`; // Prima cerca per keycloakId (caso normale dopo il primo login) let user = await User.findOne({ where: { keycloakId } }); if (!user) { // Migrazione: l'utente potrebbe esistere giĆ  per email // (creato prima che keycloakId fosse aggiunto al modello) user = await User.findOne({ where: { email } }); if (user) { await user.update({ keycloakId }); } else { user = await User.create({ keycloakId, name, email, avatarUrl, score: 0 }); } } req.userId = user.id; next(); } catch (error) { next(error); } }); }; };