Spaces:
Running
Running
| ```javascript | |
| const express = require('express'); | |
| const router = express.Router(); | |
| const bcrypt = require('bcryptjs'); | |
| const jwt = require('jsonwebtoken'); | |
| const csrf = require('csurf'); | |
| const { body, validationResult } = require('express-validator'); | |
| const User = require('../models/User'); | |
| const JWT_SECRET = process.env.JWT_SECRET || 'your_jwt_secret_here'; | |
| const csrfProtection = csrf({ cookie: true }); | |
| // Generate CSRF token | |
| router.get('/csrf-token', (req, res) => { | |
| res.json({ token: req.csrfToken() }); | |
| }); | |
| // Register endpoint | |
| router.post('/register', [ | |
| body('username').isLength({ min: 3 }).trim().escape(), | |
| body('email').isEmail().normalizeEmail(), | |
| body('password').isLength({ min: 8 }) | |
| ], async (req, res) => { | |
| const errors = validationResult(req); | |
| if (!errors.isEmpty()) { | |
| return res.status(400).json({ errors: errors.array() }); | |
| } | |
| try { | |
| const { username, email, password } = req.body; | |
| if (await User.findOne({ email })) { | |
| return res.status(400).json({ message: 'Email already exists' }); | |
| } | |
| if (await User.findOne({ username })) { | |
| return res.status(400).json({ message: 'Username already exists' }); | |
| } | |
| const hashedPassword = await bcrypt.hash(password, 12); | |
| const user = new User({ | |
| username, | |
| email, | |
| password: hashedPassword, | |
| createdAt: new Date() | |
| }); | |
| await user.save(); | |
| const token = jwt.sign( | |
| { userId: user._id }, | |
| JWT_SECRET, | |
| { expiresIn: '1h' } | |
| ); | |
| res.status(201).json({ | |
| token, | |
| user: { | |
| id: user._id, | |
| username: user.username, | |
| email: user.email | |
| } | |
| }); | |
| } catch (error) { | |
| console.error(error); | |
| res.status(500).json({ message: 'Server error' }); | |
| } | |
| }); | |
| // Login endpoint | |
| router.post('/login', [ | |
| body('email').isEmail().normalizeEmail(), | |
| body('password').exists() | |
| ], async (req, res) => { | |
| const errors = validationResult(req); | |
| if (!errors.isEmpty()) { | |
| return res.status(400).json({ errors: errors.array() }); | |
| } | |
| try { | |
| const { email, password } = req.body; | |
| const user = await User.findOne({ email }); | |
| if (!user) { | |
| return res.status(400).json({ message: 'Invalid credentials' }); | |
| } | |
| const isMatch = await bcrypt.compare(password, user.password); | |
| if (!isMatch) { | |
| return res.status(400).json({ message: 'Invalid credentials' }); | |
| } | |
| const token = jwt.sign( | |
| { userId: user._id }, | |
| JWT_SECRET, | |
| { expiresIn: '1h' } | |
| ); | |
| res.json({ | |
| token, | |
| user: { | |
| id: user._id, | |
| username: user.username, | |
| email: user.email | |
| } | |
| }); | |
| } catch (error) { | |
| console.error(error); | |
| res.status(500).json({ message: 'Server error' }); | |
| } | |
| }); | |
| // Token verification endpoint | |
| router.get('/verify', async (req, res) => { | |
| try { | |
| const token = req.header('Authorization')?.replace('Bearer ', ''); | |
| if (!token) return res.json({ valid: false }); | |
| jwt.verify(token, JWT_SECRET); | |
| res.json({ valid: true }); | |
| } catch (error) { | |
| res.json({ valid: false }); | |
| } | |
| }); | |
| // Protected route example | |
| router.get('/profile', csrfProtection, async (req, res) => { | |
| try { | |
| const token = req.header('Authorization')?.replace('Bearer ', ''); | |
| if (!token) return res.status(401).json({ message: 'Unauthorized' }); | |
| const decoded = jwt.verify(token, JWT_SECRET); | |
| const user = await User.findById(decoded.userId).select('-password'); | |
| if (!user) return res.status(404).json({ message: 'User not found' }); | |
| res.json(user); | |
| } catch (error) { | |
| console.error(error); | |
| res.status(500).json({ message: 'Server error' }); | |
| } | |
| }); | |
| module.exports = router; | |
| ``` |