commit
3efa2503ea
8 changed files with 173 additions and 0 deletions
@ -0,0 +1,8 @@ |
|||
PORT=3000 |
|||
JWT_SECRET=yourSuperSecretKey # Replace with your actual secret key |
|||
|
|||
# Database configuration |
|||
DB_HOST=localhost |
|||
DB_USER=root |
|||
DB_PASSWORD=yourpassword |
|||
DB_NAME=jwt_auth |
|||
@ -0,0 +1,4 @@ |
|||
.env |
|||
node_modules |
|||
package-lock.json |
|||
.vscode |
|||
@ -0,0 +1,11 @@ |
|||
const mysql = require('mysql2/promise'); |
|||
require('dotenv').config(); |
|||
|
|||
const pool = mysql.createPool({ |
|||
host: process.env.DB_HOST, |
|||
user: process.env.DB_USER, |
|||
password: process.env.DB_PASSWORD, |
|||
database: process.env.DB_NAME, |
|||
}); |
|||
|
|||
module.exports = pool; |
|||
@ -0,0 +1,15 @@ |
|||
const express = require('express'); |
|||
const authRoutes = require('./routes/authRoute'); |
|||
const protectedRoutes = require('./routes/protectedRoute'); |
|||
require('dotenv').config(); |
|||
|
|||
const app = express(); |
|||
|
|||
app.use(express.json()); |
|||
|
|||
app.use('/api/auth', authRoutes); |
|||
app.use('/api/protected', protectedRoutes); |
|||
|
|||
app.listen(process.env.PORT, () => { |
|||
console.log(`Server running on port ${process.env.PORT}`); |
|||
}); |
|||
@ -0,0 +1,42 @@ |
|||
const jwt = require('jsonwebtoken'); |
|||
require('dotenv').config(); |
|||
|
|||
const activeSessions = {}; // store last activity timestamp for tokens
|
|||
|
|||
module.exports = (requiredRole = null) => { |
|||
return (req, res, next) => { |
|||
const authHeader = req.headers.authorization; |
|||
|
|||
if (!authHeader) { |
|||
return res.status(401).json({ message: 'No token provided' }); |
|||
} |
|||
|
|||
const token = authHeader.split(' ')[1]; |
|||
|
|||
jwt.verify(token, process.env.JWT_SECRET, (err, decoded) => { |
|||
if (err) { |
|||
return res.status(401).json({ message: 'Invalid token' }); |
|||
} |
|||
|
|||
// Check token last activity
|
|||
const lastActivity = activeSessions[token]; |
|||
const now = Date.now(); |
|||
|
|||
if (lastActivity && now - lastActivity > 30 * 60 * 1000) { |
|||
delete activeSessions[token]; |
|||
return res.status(401).json({ message: 'Token expired due to inactivity' }); |
|||
} |
|||
|
|||
// Update last activity
|
|||
activeSessions[token] = now; |
|||
|
|||
req.user = decoded; |
|||
|
|||
if (requiredRole && decoded.role !== requiredRole) { |
|||
return res.status(403).json({ message: 'Forbidden. Insufficient role' }); |
|||
} |
|||
|
|||
next(); |
|||
}); |
|||
}; |
|||
}; |
|||
@ -0,0 +1,24 @@ |
|||
{ |
|||
"name": "api-isakafo", |
|||
"version": "1.0.0", |
|||
"main": "index.js", |
|||
"scripts": { |
|||
"test": "echo \"Error: no test specified\" && exit 1", |
|||
"start": "node index.js", |
|||
"dev": "nodemon index.js" |
|||
}, |
|||
"keywords": [], |
|||
"author": "C4M-ONG-ADM", |
|||
"license": "ISC", |
|||
"description": "backend API for Isakafo", |
|||
"dependencies": { |
|||
"bcryptjs": "^3.0.2", |
|||
"dotenv": "^17.0.0", |
|||
"express": "^5.1.0", |
|||
"jsonwebtoken": "^9.0.2", |
|||
"mysql2": "^3.14.1" |
|||
}, |
|||
"devDependencies": { |
|||
"nodemon": "^3.1.10" |
|||
} |
|||
} |
|||
@ -0,0 +1,47 @@ |
|||
const express = require('express'); |
|||
const bcrypt = require('bcryptjs'); |
|||
const jwt = require('jsonwebtoken'); |
|||
const pool = require('../config/databases'); |
|||
require('dotenv').config(); |
|||
|
|||
const router = express.Router(); |
|||
|
|||
router.post('/login', async (req, res) => { |
|||
const { username, password } = req.body; |
|||
|
|||
try { |
|||
const [rows] = await pool.query( |
|||
'SELECT * FROM users WHERE username = ?', |
|||
[username] |
|||
); |
|||
|
|||
if (rows.length === 0) { |
|||
return res.status(401).json({ message: 'Invalid credentials' }); |
|||
} |
|||
|
|||
const user = rows[0]; |
|||
|
|||
const isMatch = await bcrypt.compare(password, user.password); |
|||
|
|||
if (!isMatch) { |
|||
return res.status(401).json({ message: 'Invalid credentials' }); |
|||
} |
|||
|
|||
const payload = { |
|||
id: user.id, |
|||
username: user.username, |
|||
role: user.role, |
|||
}; |
|||
|
|||
const token = jwt.sign(payload, process.env.JWT_SECRET, { |
|||
expiresIn: '2h', // max lifespan
|
|||
}); |
|||
|
|||
res.json({ token }); |
|||
} catch (err) { |
|||
console.error(err); |
|||
res.status(500).json({ message: 'Server error' }); |
|||
} |
|||
}); |
|||
|
|||
module.exports = router; |
|||
@ -0,0 +1,22 @@ |
|||
const express = require('express'); |
|||
const authMiddleware = require('../middleware/authMiddleware'); |
|||
|
|||
const router = express.Router(); |
|||
|
|||
// Open only to logged users
|
|||
router.get('/profile', authMiddleware(), (req, res) => { |
|||
res.json({ |
|||
message: 'Welcome to your profile!', |
|||
user: req.user, |
|||
}); |
|||
}); |
|||
|
|||
// Open only to admins
|
|||
router.get('/admin', authMiddleware('admin'), (req, res) => { |
|||
res.json({ |
|||
message: 'Welcome, admin!', |
|||
user: req.user, |
|||
}); |
|||
}); |
|||
|
|||
module.exports = router; |
|||
Loading…
Reference in new issue