helpyourneighbour/backend/src/routes/auth.js

54 lines
1.9 KiB
JavaScript
Raw Normal View History

import { Router } from 'express';
import bcrypt from 'bcryptjs';
import jwt from 'jsonwebtoken';
import { z } from 'zod';
import { pool } from '../db/connection.js';
const router = Router();
const registerSchema = z.object({
email: z.string().email(),
password: z.string().min(8),
displayName: z.string().min(2).max(120)
});
router.post('/register', async (req, res) => {
const parsed = registerSchema.safeParse(req.body);
if (!parsed.success) return res.status(400).json({ error: parsed.error.flatten() });
const { email, password, displayName } = parsed.data;
const passwordHash = await bcrypt.hash(password, 12);
try {
const [result] = await pool.query(
'INSERT INTO users (email, password_hash, display_name) VALUES (?, ?, ?)',
[email, passwordHash, displayName]
);
const token = jwt.sign({ userId: result.insertId, email }, process.env.JWT_SECRET, { expiresIn: '7d' });
return res.status(201).json({ token });
} catch (err) {
if (err.code === 'ER_DUP_ENTRY') return res.status(409).json({ error: 'Email already exists' });
return res.status(500).json({ error: 'Registration failed' });
}
});
router.post('/login', async (req, res) => {
const parsed = z.object({ email: z.string().email(), password: z.string().min(1) }).safeParse(req.body);
if (!parsed.success) return res.status(400).json({ error: parsed.error.flatten() });
const { email, password } = parsed.data;
const [rows] = await pool.query('SELECT id, email, password_hash FROM users WHERE email = ? LIMIT 1', [email]);
const user = rows[0];
if (!user) return res.status(401).json({ error: 'Invalid credentials' });
const ok = await bcrypt.compare(password, user.password_hash);
if (!ok) return res.status(401).json({ error: 'Invalid credentials' });
const token = jwt.sign({ userId: user.id, email: user.email }, process.env.JWT_SECRET, { expiresIn: '7d' });
return res.json({ token });
});
export default router;