Added comprehensive authentication and authorization system: Authentication System: - Better Auth integration with session management - Login/logout pages and API routes - Middleware for route protection - Auth utilities and client libraries User Management: - User list, detail, and invite pages - User API endpoints (CRUD operations) - Session management for users - Profile settings page Role-Based Access Control: - Role management pages (list, create, edit) - Permission system with granular controls - Role assignment to users - Role API endpoints Admin Features: - Audit log page for tracking system events - Admin settings page - Audit service for logging user actions Additional Features: - Quotes management pages and components - SalesBldr API integration - Email service for notifications Configuration & Documentation: - Updated docker-compose.yml - MCP server configuration (mcp.json) - CVE-2025-55182 security review documentation - Standards guide and PRD documents - Re-enabling authentication documentation Database Migrations: - 012: Auth tables (users, sessions, accounts, verifications) - 013: Role tables (roles, permissions, role_permissions, user_roles) - 014: Admin settings table UI Updates: - Updated dashboard layout - Enhanced app layout with auth integration
169 lines
3.6 KiB
TypeScript
169 lines
3.6 KiB
TypeScript
import { headers } from "next/headers";
|
|
import { NextResponse } from "next/server";
|
|
import { auth } from "./auth";
|
|
import { hasPermission, type Permission } from "./permissions";
|
|
|
|
// Extended user type with custom fields
|
|
type UserWithRole = {
|
|
id: string;
|
|
email: string;
|
|
name: string;
|
|
role?: string;
|
|
requires_setup?: boolean;
|
|
[key: string]: unknown;
|
|
};
|
|
|
|
/**
|
|
* Get the current session from the request headers
|
|
* Use this in API routes and server components
|
|
*/
|
|
export async function getSession() {
|
|
const session = await auth.api.getSession({
|
|
headers: await headers(),
|
|
});
|
|
return session;
|
|
}
|
|
|
|
/**
|
|
* Require authentication for an API route
|
|
* Returns the session if authenticated, or a 401 response if not
|
|
*/
|
|
export async function requireAuth() {
|
|
const session = await getSession();
|
|
|
|
if (!session) {
|
|
return {
|
|
session: null,
|
|
error: NextResponse.json(
|
|
{ error: "Unauthorized" },
|
|
{ status: 401 }
|
|
),
|
|
};
|
|
}
|
|
|
|
return { session, error: null };
|
|
}
|
|
|
|
/**
|
|
* Require specific permissions for an API route
|
|
* Returns the session if authorized, or a 403 response if not
|
|
*/
|
|
export async function requirePermission(
|
|
resource: Permission["resource"],
|
|
action: string
|
|
) {
|
|
const { session, error } = await requireAuth();
|
|
|
|
if (error) {
|
|
return { session: null, error };
|
|
}
|
|
|
|
const userRole = (session!.user as UserWithRole).role || "user";
|
|
|
|
if (!hasPermission(userRole, resource, action)) {
|
|
return {
|
|
session: null,
|
|
error: NextResponse.json(
|
|
{ error: "Forbidden" },
|
|
{ status: 403 }
|
|
),
|
|
};
|
|
}
|
|
|
|
return { session, error: null };
|
|
}
|
|
|
|
/**
|
|
* Require admin or super-admin role
|
|
*/
|
|
export async function requireAdmin() {
|
|
const { session, error } = await requireAuth();
|
|
|
|
if (error) {
|
|
return { session: null, error };
|
|
}
|
|
|
|
const userRole = (session!.user as UserWithRole).role || "user";
|
|
|
|
if (userRole !== "admin" && userRole !== "super-admin") {
|
|
return {
|
|
session: null,
|
|
error: NextResponse.json(
|
|
{ error: "Forbidden - Admin access required" },
|
|
{ status: 403 }
|
|
),
|
|
};
|
|
}
|
|
|
|
return { session, error: null };
|
|
}
|
|
|
|
/**
|
|
* Require super-admin role
|
|
*/
|
|
export async function requireSuperAdmin() {
|
|
const { session, error } = await requireAuth();
|
|
|
|
if (error) {
|
|
return { session: null, error };
|
|
}
|
|
|
|
const userRole = (session!.user as UserWithRole).role || "user";
|
|
|
|
if (userRole !== "super-admin") {
|
|
return {
|
|
session: null,
|
|
error: NextResponse.json(
|
|
{ error: "Forbidden - Super admin access required" },
|
|
{ status: 403 }
|
|
),
|
|
};
|
|
}
|
|
|
|
return { session, error: null };
|
|
}
|
|
|
|
/**
|
|
* Check if the current user has a specific permission
|
|
* Use this in server components for conditional rendering
|
|
*/
|
|
export async function checkPermission(
|
|
resource: Permission["resource"],
|
|
action: string
|
|
): Promise<boolean> {
|
|
const session = await getSession();
|
|
|
|
if (!session) {
|
|
return false;
|
|
}
|
|
|
|
const userRole = (session.user as UserWithRole).role || "user";
|
|
return hasPermission(userRole, resource, action);
|
|
}
|
|
|
|
/**
|
|
* Check if the current user is an admin or super-admin
|
|
*/
|
|
export async function isAdmin(): Promise<boolean> {
|
|
const session = await getSession();
|
|
|
|
if (!session) {
|
|
return false;
|
|
}
|
|
|
|
const userRole = (session.user as UserWithRole).role || "user";
|
|
return userRole === "admin" || userRole === "super-admin";
|
|
}
|
|
|
|
/**
|
|
* Check if the current user is a super-admin
|
|
*/
|
|
export async function isSuperAdmin(): Promise<boolean> {
|
|
const session = await getSession();
|
|
|
|
if (!session) {
|
|
return false;
|
|
}
|
|
|
|
return (session.user as UserWithRole).role === "super-admin";
|
|
}
|