web/server/collab-auth.tsblame
View source
0b4b5821import { parse as parseCookie } from "cookie";
0b4b5822
0b4b5823const GROVE_HUB_API_URL =
0b4b5824 process.env.GROVE_HUB_API_URL || "http://localhost:4001";
0b4b5825
0b4b5826/**
0b4b5827 * Verify a token by calling the hub-api (the authority that issued it).
0b4b5828 * Returns the user object on success, throws on failure.
0b4b5829 */
0b4b58210export async function verifyToken(token: string): Promise<any> {
0b4b58211 const res = await fetch(`${GROVE_HUB_API_URL}/api/auth/me`, {
0b4b58212 headers: { Authorization: `Bearer ${token}` },
0b4b58213 });
0b4b58214 if (!res.ok) throw new Error(`hub-api returned ${res.status}`);
0b4b58215 const data = await res.json();
0b4b58216 return data.user;
0b4b58217}
0b4b58218
0b4b58219export function extractToken(req: Request): string | null {
0b4b58220 // 1. Authorization header
0b4b58221 const authHeader = req.headers.get("authorization");
0b4b58222 if (authHeader?.startsWith("Bearer ")) {
0b4b58223 return authHeader.slice(7);
0b4b58224 }
0b4b58225 // 2. Cookie
0b4b58226 const cookieHeader = req.headers.get("cookie");
0b4b58227 if (cookieHeader) {
0b4b58228 const cookies = parseCookie(cookieHeader);
0b4b58229 if (cookies.grove_hub_token) return cookies.grove_hub_token;
0b4b58230 }
0b4b58231 return null;
0b4b58232}
0b4b58233
0b4b58234// Socket.IO middleware for /collab namespace
0b4b58235export function socketAuth(
0b4b58236 socket: { handshake: { auth?: { token?: string }; headers?: { cookie?: string } }; user?: any; token?: string },
0b4b58237 next: (err?: Error) => void
0b4b58238) {
0b4b58239 // 1. Handshake auth (client passes { auth: { token } })
0b4b58240 let token = socket.handshake.auth?.token;
0b4b58241 // 2. Fallback to cookie
0b4b58242 if (!token) {
0b4b58243 const cookieHeader = socket.handshake.headers?.cookie;
0b4b58244 if (cookieHeader) {
0b4b58245 const cookies = parseCookie(cookieHeader);
0b4b58246 token = cookies.grove_hub_token;
0b4b58247 }
0b4b58248 }
0b4b58249 if (!token) return next(new Error("unauthorized"));
0b4b58250 verifyToken(token)
0b4b58251 .then((user) => {
0b4b58252 socket.user = user;
0b4b58253 socket.token = token!;
0b4b58254 next();
0b4b58255 })
0b4b58256 .catch(() => {
0b4b58257 next(new Error("unauthorized"));
0b4b58258 });
0b4b58259}