Files
KiraTV-APP-NodeCast-Modific…/server/auth.js
T
2026-01-01 15:36:38 -05:00

152 lines
3.7 KiB
JavaScript

const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const passport = require('passport');
const { Strategy: JwtStrategy, ExtractJwt } = require('passport-jwt');
const { Strategy: LocalStrategy } = require('passport-local');
/**
* Authentication and Authorization Module
* Handles user authentication, session management, and role-based access control
* Using Passport.js with JWT tokens
*/
// JWT Secret - In production, use environment variable
const JWT_SECRET = process.env.JWT_SECRET || 'nodecast-tv-secret-key-change-in-production';
const JWT_EXPIRY = '24h';
/**
* Hash password using bcrypt
*/
async function hashPassword(password) {
const salt = await bcrypt.genSalt(10);
return bcrypt.hash(password, salt);
}
/**
* Verify password against hash
*/
async function verifyPassword(password, hash) {
return bcrypt.compare(password, hash);
}
/**
* Generate JWT token
*/
function generateToken(user) {
return jwt.sign(
{
id: user.id,
username: user.username,
role: user.role
},
JWT_SECRET,
{ expiresIn: JWT_EXPIRY }
);
}
/**
* Verify JWT token
*/
function verifyToken(token) {
try {
return jwt.verify(token, JWT_SECRET);
} catch (err) {
return null;
}
}
/**
* Configure Passport Local Strategy for username/password authentication
*/
function configureLocalStrategy(getUserByUsername, verifyUserPassword) {
passport.use(new LocalStrategy(
async (username, password, done) => {
try {
const user = await getUserByUsername(username);
if (!user) {
return done(null, false, { message: 'Invalid credentials' });
}
const isValid = await verifyUserPassword(password, user.passwordHash);
if (!isValid) {
return done(null, false, { message: 'Invalid credentials' });
}
return done(null, user);
} catch (err) {
return done(err);
}
}
));
}
/**
* Configure Passport JWT Strategy for token-based authentication
*/
function configureJwtStrategy(getUserById) {
const options = {
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: JWT_SECRET
};
passport.use(new JwtStrategy(options, async (payload, done) => {
try {
const user = await getUserById(payload.id);
if (!user) {
return done(null, false);
}
return done(null, {
id: user.id,
username: user.username,
role: user.role
});
} catch (err) {
return done(err, false);
}
}));
}
/**
* Middleware: Require authentication using Passport JWT
*/
const requireAuth = passport.authenticate('jwt', { session: false });
/**
* Middleware: Require admin role
*/
function requireAdmin(req, res, next) {
if (!req.user || req.user.role !== 'admin') {
return res.status(403).json({ error: 'Forbidden - Admin access required' });
}
next();
}
/**
* Middleware: Check for specific role
*/
function requireRole(role) {
return (req, res, next) => {
if (!req.user || req.user.role !== role) {
return res.status(403).json({ error: `Forbidden - ${role} access required` });
}
next();
};
}
module.exports = {
passport,
hashPassword,
verifyPassword,
generateToken,
verifyToken,
configureLocalStrategy,
configureJwtStrategy,
requireAuth,
requireAdmin,
requireRole
};