feat: add authentication, user management, and admin features
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
This commit is contained in:
parent
d8e6931b85
commit
9f912aed24
68 changed files with 7651 additions and 3 deletions
169
lib/auth-utils.ts
Normal file
169
lib/auth-utils.ts
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
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";
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue