Spaces:
Sleeping
Sleeping
| import { Request, Response, NextFunction } from 'express'; | |
| import { supabase } from '../../db/client'; | |
| import { logger } from '../../utils/logger'; | |
| /** Augmented Express Request with authenticated user fields */ | |
| export interface AuthenticatedRequest extends Request { | |
| userId: string; | |
| userEmail: string; | |
| } | |
| /** | |
| * Express middleware that verifies a Supabase JWT from the Authorization header. | |
| * On success, sets req.userId and req.userEmail for downstream handlers. | |
| * Returns 401 if the token is missing or invalid. | |
| */ | |
| export async function authenticateUser( | |
| req: Request, | |
| res: Response, | |
| next: NextFunction, | |
| ): Promise<void> { | |
| const authHeader = req.headers.authorization; | |
| if (!authHeader || !authHeader.startsWith('Bearer ')) { | |
| res.status(401).json({ error: 'Missing or malformed Authorization header' }); | |
| return; | |
| } | |
| const token = authHeader.slice(7); // Strip "Bearer " | |
| try { | |
| const { data, error } = await supabase.auth.getUser(token); | |
| if (error || !data.user) { | |
| logger.warn('Auth verification failed', { error: error?.message }); | |
| res.status(401).json({ error: 'Invalid or expired token' }); | |
| return; | |
| } | |
| // Attach user info to the request | |
| (req as AuthenticatedRequest).userId = data.user.id; | |
| (req as AuthenticatedRequest).userEmail = data.user.email || ''; | |
| next(); | |
| } catch (err) { | |
| logger.error('Auth middleware unexpected error', { | |
| error: err instanceof Error ? err.message : String(err), | |
| }); | |
| res.status(401).json({ error: 'Authentication failed' }); | |
| } | |
| } | |