secutorpro commited on
Commit
ce89c62
·
verified ·
1 Parent(s): b8a98f2

JWT auth: login route + requireAuth middleware

Browse files
Files changed (1) hide show
  1. server/src/auth.js +47 -0
server/src/auth.js ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { Router } from 'express';
2
+ import jwt from 'jsonwebtoken';
3
+ import bcrypt from 'bcryptjs';
4
+ import crypto from 'node:crypto';
5
+ import fs from 'node:fs';
6
+ import path from 'node:path';
7
+ import db from './db.js';
8
+
9
+ const DATA_DIR = process.env.DATA_DIR || path.join(process.cwd(), 'data');
10
+ fs.mkdirSync(DATA_DIR, { recursive: true });
11
+
12
+ function loadSecret() {
13
+ if (process.env.JWT_SECRET) return process.env.JWT_SECRET;
14
+ const file = path.join(DATA_DIR, 'jwt-secret');
15
+ if (fs.existsSync(file)) return fs.readFileSync(file, 'utf8').trim();
16
+ const secret = crypto.randomBytes(32).toString('hex');
17
+ fs.writeFileSync(file, secret, { mode: 0o600 });
18
+ return secret;
19
+ }
20
+
21
+ export const JWT_SECRET = loadSecret();
22
+
23
+ const r = Router();
24
+
25
+ r.post('/login', (req, res) => {
26
+ const { username, password } = req.body || {};
27
+ const u = db.prepare('SELECT * FROM users WHERE username = ?').get(String(username || ''));
28
+ if (!u || !bcrypt.compareSync(String(password || ''), u.password_hash)) {
29
+ return res.status(401).json({ error: 'Invalid username or password' });
30
+ }
31
+ const token = jwt.sign({ sub: u.id, username: u.username, role: u.role }, JWT_SECRET, { expiresIn: '12h' });
32
+ res.json({ token, user: { id: u.id, username: u.username, role: u.role } });
33
+ });
34
+
35
+ export function requireAuth(req, res, next) {
36
+ const header = req.headers.authorization || '';
37
+ const token = header.startsWith('Bearer ') ? header.slice(7) : null;
38
+ if (!token) return res.status(401).json({ error: 'Missing token' });
39
+ try {
40
+ req.user = jwt.verify(token, JWT_SECRET);
41
+ next();
42
+ } catch {
43
+ res.status(401).json({ error: 'Invalid or expired token' });
44
+ }
45
+ }
46
+
47
+ export default r;