Add auth role to api
This commit is contained in:
1 parent
9a476d9b86
commit
f27d87531c
6 files changed
+364
No files matched your search
@@ -0,0 +1,92 @@
|
||||
import { Router, Request, Response } from 'express';
|
||||
import { Pool } from 'pg';
|
||||
import { AuthService } from './auth.service.ts';
|
||||
|
||||
export function createAuthRouter(db: Pool, authService: AuthService): Router {
|
||||
const router = Router();
|
||||
|
||||
/**
|
||||
* POST /api/auth/register
|
||||
*/
|
||||
router.post('/register', async (req: Request, res: Response): Promise<void> => {
|
||||
try {
|
||||
const { username, password } = req.body;
|
||||
|
||||
if (!username || !password || username.trim() === '' || password.length < 8) {
|
||||
res.status(400).json({ success: false, error: 'Username required, and password must be at least 8 characters long.' });
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if user already exists
|
||||
const checkUser = await db.query('SELECT id FROM users WHERE username = $1;', [username]);
|
||||
if (checkUser.rows.length > 0) {
|
||||
res.status(409).json({ success: false, error: 'Username is already taken.' });
|
||||
return;
|
||||
}
|
||||
|
||||
// Hash password using Argon2id
|
||||
const hash = await authService.hashPassword(password);
|
||||
|
||||
// Save user
|
||||
await db.query('INSERT INTO users (username, password_hash) VALUES ($1, $2);', [username, hash]);
|
||||
|
||||
res.status(201).json({ success: true, message: 'User registered successfully!' });
|
||||
} catch (error) {
|
||||
console.error('Registration failure:', error);
|
||||
res.status(500).json({ success: false, error: 'Internal Server Error' });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* POST /api/auth/login
|
||||
*/
|
||||
router.post('/login', async (req: Request, res: Response): Promise<void> => {
|
||||
try {
|
||||
const { username, password } = req.body;
|
||||
|
||||
if (!username || !password) {
|
||||
res.status(400).json({ success: false, error: 'Username and password are required.' });
|
||||
return;
|
||||
}
|
||||
|
||||
const result = await db.query('SELECT id, password_hash FROM users WHERE username = $1;', [username]);
|
||||
if (result.rows.length === 0) {
|
||||
res.status(401).json({ success: false, error: 'Invalid username or password.' });
|
||||
return;
|
||||
}
|
||||
|
||||
const user = result.rows[0];
|
||||
const validPassword = await authService.verifyPassword(password, user.password_hash);
|
||||
|
||||
if (!validPassword) {
|
||||
res.status(401).json({ success: false, error: 'Invalid username or password.' });
|
||||
return;
|
||||
}
|
||||
|
||||
// Generate a high-entropy session token
|
||||
const sessionToken = authService.generateSessionToken();
|
||||
const expiresAt = new Date(Date.now() + 30 * 24 * 60 * 60 * 1000); // Expires in 30 days
|
||||
|
||||
// Store the session securely in the database
|
||||
await db.query(
|
||||
'INSERT INTO sessions (id, user_id, expires_at) VALUES ($1, $2, $3);',
|
||||
[sessionToken, user.id, expiresAt]
|
||||
);
|
||||
|
||||
// Issue the secure HttpOnly cookie
|
||||
res.cookie('session_token', sessionToken, {
|
||||
httpOnly: true,
|
||||
secure: process.env.NODE_ENV === 'production', // Requires HTTPS in production
|
||||
sameSite: 'strict',
|
||||
expires: expiresAt,
|
||||
});
|
||||
|
||||
res.json({ success: true, message: 'Logged in successfully!' });
|
||||
} catch (error) {
|
||||
console.error('Login failure:', error);
|
||||
res.status(500).json({ success: false, error: 'Internal Server Error' });
|
||||
}
|
||||
});
|
||||
|
||||
return router;
|
||||
}
|
||||
Reference in new issue
Block a user