// Authentication middleware import type { User } from '@vibncode/shared'; import { eq } from 'drizzle-orm'; import type { Context } from 'hono'; import { createMiddleware } from 'hono/factory'; import { db } from '../db/client'; import { users } from '../db/schema'; import { extractTokenFromHeader, verifyToken } from '../lib/jwt'; import type { HonoContext } from '../types/context'; import type { DbUser } from '../types/database'; /** * Map database user to API user format */ function mapDbUserToUser(user: DbUser): User { return { id: user.id, name: user.name, email: user.email || undefined, avatarUrl: user.avatarUrl || undefined, displayName: user.displayName || undefined, oauthProvider: user.githubId ? 'github' : 'google', oauthId: (user.githubId || user.googleId) ?? '', createdAt: new Date(user.createdAt).toISOString(), updatedAt: new Date(user.updatedAt).toISOString(), }; } /** * Authentication middleware * Validates JWT token and loads user from database */ export const authMiddleware = createMiddleware(async (c, next) => { const authorization = c.req.header('Authorization'); const token = extractTokenFromHeader(authorization); if (!token) { return c.json({ error: 'Unauthorized: No token provided' }, 401); } const payload = await verifyToken(token, c.env); if (!payload || !payload.userId) { return c.json({ error: 'Unauthorized: Invalid token' }, 401); } // Load user from database try { const [user] = await db.select().from(users).where(eq(users.id, payload.userId)).limit(1); if (!user) { return c.json({ error: 'Unauthorized: User not found' }, 401); } // Set user in context c.set('user', mapDbUserToUser(user)); c.set('userId', user.id); } catch (error) { console.error('Error loading user:', error); return c.json({ error: 'Internal server error' }, 500); } await next(); }); /** * Optional authentication middleware * Does not fail if no token is provided, but loads user if available */ export const optionalAuthMiddleware = createMiddleware(async (c, next) => { const authorization = c.req.header('Authorization'); const token = extractTokenFromHeader(authorization); if (token) { const payload = await verifyToken(token, c.env); if (payload?.userId) { try { const [user] = await db.select().from(users).where(eq(users.id, payload.userId)).limit(1); if (user) { c.set('user', mapDbUserToUser(user)); c.set('userId', user.id); } } catch (error) { console.error('Error loading user:', error); } } } await next(); }); /** * Helper function to get authenticated user and userId * Use this after authMiddleware */ export function getAuth(c: Context): { userId: string; user: User } { const userId = c.get('userId'); const user = c.get('user'); if (!userId || !user) { throw new Error('Unauthorized'); } return { userId, user }; } /** * Helper function to get optional authenticated user * Use this after optionalAuthMiddleware */ export function getOptionalAuth(c: Context): { userId: string; user: User } | null { const userId = c.get('userId'); const user = c.get('user'); if (!userId || !user) { return null; } return { userId, user }; }