import { Router, Request, Response } from 'express';
import { AuthService } from '../auth/auth.js';
import { ApiKeyService } from '../auth/api-key-service.js';
import pg from 'pg';
export function createAuthRoutes(pool: pg.Pool): Router {
const router = Router();
const authService = new AuthService(pool);
const apiKeyService = new ApiKeyService(pool);
// POST /api/admin/users - Create user (admin only)
router.post('/admin/users', async (req: Request, res: Response) => {
try {
const adminSecret = req.headers['x-admin-secret'] as string;
const expectedSecret = process.env.ADMIN_SECRET;
if (!expectedSecret) {
res.status(503).json({ error: 'Admin endpoint not configured. Set ADMIN_SECRET env var.' });
return;
}
if (adminSecret !== expectedSecret) {
res.status(403).json({ error: 'Invalid admin secret' });
return;
}
const { username, email, password } = req.body;
if (!username || !email || !password) {
res.status(400).json({ error: 'Username, email, and password required' });
return;
}
if (password.length < 8) {
res.status(400).json({ error: 'Password must be at least 8 characters' });
return;
}
const userId = await authService.createUser(username, email, password);
// Create default API key for new user
const apiKey = await apiKeyService.createApiKey(userId, 'Default Key');
res.status(201).json({
message: 'User created successfully',
userId,
username,
apiKey
});
} catch (error: any) {
if (error.code === '23505') {
res.status(409).json({ error: 'Username or email already exists' });
return;
}
console.error('User creation error:', error);
res.status(500).json({ error: 'Failed to create user' });
}
});
// POST /api/auth/login - Login
router.post('/login', async (req: Request, res: Response) => {
try {
const { username, password } = req.body;
if (!username || !password) {
res.status(400).json({ error: 'Username and password required' });
return;
}
const user = await authService.validateUser(username, password);
if (!user) {
res.status(401).json({ error: 'Invalid credentials' });
return;
}
// Set session
req.session.userId = user.id;
req.session.username = user.username;
res.json({ message: 'Login successful', username: user.username });
} catch (error) {
console.error('Login error:', error);
res.status(500).json({ error: 'Login failed' });
}
});
// POST /api/auth/logout - Logout
router.post('/logout', (req: Request, res: Response) => {
req.session.destroy((err) => {
if (err) {
res.status(500).json({ error: 'Logout failed' });
return;
}
res.clearCookie('connect.sid');
res.json({ message: 'Logged out successfully' });
});
});
// GET /api/auth/me - Get current user info
router.get('/me', async (req: Request, res: Response) => {
if (!req.session?.userId) {
res.status(401).json({ error: 'Not authenticated' });
return;
}
const user = await authService.getUserById(req.session.userId);
if (!user) {
res.status(401).json({ error: 'User not found' });
return;
}
res.json({ userId: user.id, username: user.username, email: user.email });
});
// GET /api/auth/keys - List user's API keys
router.get('/keys', async (req: Request, res: Response) => {
if (!req.session?.userId) {
res.status(401).json({ error: 'Not authenticated' });
return;
}
const keys = await apiKeyService.getApiKeys(req.session.userId);
// Mask API keys for security (show only first 8 + last 4 chars)
const maskedKeys = keys.map(k => ({
...k,
api_key_masked: k.api_key.substring(0, 8) + '...' + k.api_key.slice(-4),
api_key: undefined
}));
res.json({ keys: maskedKeys });
});
// GET /api/auth/keys/:id/reveal - Get full API key
router.get('/keys/:id/reveal', async (req: Request, res: Response) => {
if (!req.session?.userId) {
res.status(401).json({ error: 'Not authenticated' });
return;
}
const keyId = parseInt(req.params.id);
const apiKey = await apiKeyService.getFullApiKey(req.session.userId, keyId);
if (!apiKey) {
res.status(404).json({ error: 'API key not found' });
return;
}
res.json({ api_key: apiKey });
});
// POST /api/auth/keys - Create new API key
router.post('/keys', async (req: Request, res: Response) => {
if (!req.session?.userId) {
res.status(401).json({ error: 'Not authenticated' });
return;
}
const { name } = req.body;
const apiKey = await apiKeyService.createApiKey(req.session.userId, name || 'New Key');
res.status(201).json({ api_key: apiKey, message: 'Save this key - it will only be shown once!' });
});
// DELETE /api/auth/keys/:id - Revoke API key
router.delete('/keys/:id', async (req: Request, res: Response) => {
if (!req.session?.userId) {
res.status(401).json({ error: 'Not authenticated' });
return;
}
const keyId = parseInt(req.params.id);
const success = await apiKeyService.revokeApiKey(req.session.userId, keyId);
if (success) {
res.json({ message: 'API key revoked' });
} else {
res.status(404).json({ error: 'API key not found' });
}
});
return router;
}