learning_ai_common_plat/dashboards/admin-web/src/lib/auth-server.ts
saravanakumardb1 ce0074d6ee fix(admin-web): proxy routes + pages use cookie-based auth
- Add getCurrentUserFromRequest() to auth-server.ts (checks cookies first, then Authorization header)
- Update all 34 proxy routes: getCurrentUser(req.headers.get('authorization')) → getCurrentUserFromRequest(req)
- Add createProxyFetch() shared helper in lib/proxy-fetch.ts (injects auth + product-id headers)
- Update 15 admin pages: replace inline fetch helpers with createProxyFetch
- Root cause: newer pages used bare fetch() without Authorization headers, causing 401s on all proxy routes
2026-03-21 20:31:30 -07:00

85 lines
2.6 KiB
TypeScript

/**
* Server-side auth utilities — proxies to platform-service for token verification.
* Used by Next.js API routes only (never imported in client components).
*
* All JWT signing/verification is handled by platform-service (single auth source).
* This module provides helper functions that verify tokens via platform-service
* and return a lightweight UserDoc for use in API route guards.
*/
import { hashPassword, verifyPassword } from '@bytelyst/auth';
import { getMeViaService } from '@/lib/platform-client';
export { hashPassword, verifyPassword };
export interface UserDoc {
id: string;
email: string;
name: string;
role: string;
plan: string;
status?: string;
}
/**
* Get the current user from an Authorization header value.
* Verifies the token via platform-service /auth/me.
*/
export async function getCurrentUser(authHeader: string | null): Promise<UserDoc | null> {
if (!authHeader?.startsWith('Bearer ')) return null;
const token = authHeader.slice(7);
try {
const user = await getMeViaService(token);
return {
id: user.id,
email: user.email,
name: user.displayName,
role: user.role,
plan: user.plan,
};
} catch {
return null;
}
}
/**
* Get the current user from a Request object.
* Checks cookies first (Next.js httpOnly cookie), then Authorization header.
* Returns null if not authenticated.
*/
export async function getCurrentUserFromRequest(request: Request): Promise<UserDoc | null> {
const cookieHeader = request.headers.get('cookie') || '';
const tokenMatch = cookieHeader.match(/(?:^|;\s*)token=([^;]+)/);
const authHeader = request.headers.get('authorization');
if (tokenMatch) {
return getCurrentUser(`Bearer ${tokenMatch[1]}`);
}
if (authHeader) {
return getCurrentUser(authHeader);
}
return null;
}
/**
* Require an admin user from the request. Checks cookies first, then Authorization header.
* Throws Error("Unauthorized") if not authenticated or not admin/super_admin role.
*/
export async function requireAdmin(request: Request): Promise<UserDoc> {
// Try cookie first (Next.js httpOnly cookie), then Authorization header
const cookieHeader = request.headers.get('cookie') || '';
const tokenMatch = cookieHeader.match(/(?:^|;\s*)token=([^;]+)/);
const authHeader = request.headers.get('authorization');
let user: UserDoc | null = null;
if (tokenMatch) {
user = await getCurrentUser(`Bearer ${tokenMatch[1]}`);
} else if (authHeader) {
user = await getCurrentUser(authHeader);
}
if (!user) throw new Error('Unauthorized');
if (!['admin', 'super_admin'].includes(user.role)) throw new Error('Unauthorized');
return user;
}