Files
panel/AUTHORIZATION_IMPLEMENTATION.md

22 KiB

Authorization Implementation Guide

Project Overview

This document outlines the implementation strategy for adding authentication and authorization to the Project Management Panel - a Next.js 15 application with SQLite database.

Current State Analysis (Updated: June 25, 2025)

What We Have Implemented

  • Framework: Next.js 15 with App Router
  • Database: SQLite with better-sqlite3
  • Authentication: NextAuth.js v5 with credentials provider
  • User Management: Complete user CRUD operations with bcrypt password hashing
  • Database Schema: Users table with roles, audit logs, sessions
  • API Protection: Middleware system with role-based access control
  • Session Management: JWT-based sessions with 30-day expiration
  • Security Features: Account lockout, failed login tracking, password validation
  • UI Components: Authentication provider, navigation with user context
  • Auth Pages: Sign-in page implemented

What's Protected

  • API Routes: All major endpoints (projects, contracts, tasks, notes) are protected
  • Role Hierarchy: admin > project_manager > user > read_only
  • Navigation: Role-based menu items (admin sees user management)
  • Session Security: Automatic session management and validation

🔄 Partially Implemented

  • Auth Pages: Sign-in exists, missing sign-out and error pages
  • User Interface: Basic auth integration, could use more polish
  • Admin Features: User management backend exists, UI needs completion
  • Audit Logging: Database schema exists, not fully integrated

Still Missing

  • Complete user management UI for admins
  • Password reset functionality
  • Rate limiting implementation
  • Enhanced input validation schemas
  • CSRF protection
  • Security headers middleware
  • Comprehensive error handling
  • Email notifications

1. Authentication Solution: NextAuth.js

Why NextAuth.js?

  • Native Next.js 15 App Router support
  • Database session management
  • Built-in security features (CSRF, JWT handling)
  • Flexible provider system
  • SQLite adapter available

2. Role-Based Access Control (RBAC)

Proposed User Roles:

Role Permissions Use Case
Admin Full system access, user management System administrators
Project Manager Manage all projects/tasks, view reports Team leads, supervisors
User View/edit assigned projects/tasks Regular employees
Read-only View-only access to data Clients, stakeholders

Implementation Status

Phase 1: Foundation Setup - COMPLETED

1.1 Dependencies - INSTALLED

  • NextAuth.js v5 (beta)
  • bcryptjs for password hashing
  • Zod for validation
  • Better-sqlite3 adapter compatibility

1.2 Environment Configuration - COMPLETED

  • .env.local configured with NEXTAUTH_SECRET and NEXTAUTH_URL
  • Database URL configuration
  • Development environment setup

1.3 Database Schema - IMPLEMENTED

  • Users table with roles and security features
  • Sessions table for NextAuth.js
  • Audit logs table for security tracking
  • Proper indexes for performance

1.4 Initial Admin User - COMPLETED

  • scripts/create-admin.js script available
  • Default admin user: admin@localhost.com / admin123456

Phase 2: Authentication Core - COMPLETED

2.1 NextAuth.js Configuration - IMPLEMENTED

  • File: src/lib/auth.js
  • Credentials provider with email/password
  • JWT session strategy with 30-day expiration
  • Account lockout after 5 failed attempts (15-minute lockout)
  • Password verification with bcrypt
  • Failed login attempt tracking
  • Session callbacks for role management

2.2 API Route Handlers - IMPLEMENTED

  • File: src/app/api/auth/[...nextauth]/route.js
  • NextAuth.js handlers properly configured

2.3 User Management System - IMPLEMENTED

  • File: src/lib/userManagement.js
  • Complete CRUD operations for users
  • Password hashing and validation
  • Role management functions
  • User lookup by ID and email

Phase 3: Authorization Middleware - COMPLETED

3.1 API Protection Middleware - IMPLEMENTED

  • File: src/lib/middleware/auth.js
  • withAuth() function for protecting routes
  • Role hierarchy enforcement (admin=4, project_manager=3, user=2, read_only=1)
  • Helper functions: withReadAuth, withUserAuth, withAdminAuth, withManagerAuth
  • Proper error handling and status codes

3.2 Protected API Routes - IMPLEMENTED

Example in src/app/api/projects/route.js:

  • GET requests require read_only access
  • POST requests require user access
  • All major API endpoints are protected

3.3 Session Provider - IMPLEMENTED

  • File: src/components/auth/AuthProvider.js
  • NextAuth SessionProvider wrapper
  • Integrated into root layout

🔄 Phase 4: User Interface - PARTIALLY COMPLETED

4.1 Authentication Pages - 🔄 PARTIAL

  • Sign-in page: src/app/auth/signin/page.js - Complete with form validation
  • Sign-out page: Missing
  • 🔄 Error page: src/app/auth/error/page.js - Basic implementation
  • Unauthorized page: Missing

4.2 Navigation Updates - COMPLETED

  • File: src/components/ui/Navigation.js
  • User session integration with useSession
  • Role-based menu items (admin sees user management)
  • Sign-out functionality
  • Conditional rendering based on auth status

4.3 User Management Interface - MISSING

  • Backend exists in userManagement.js
  • Admin UI for user CRUD operations needed
  • Role assignment interface needed

Phase 5: Security Enhancements - NOT STARTED

5.1 Input Validation Schemas - MISSING

  • Zod schemas for API endpoints
  • Request validation middleware

5.2 Rate Limiting - MISSING

  • Rate limiting middleware
  • IP-based request tracking

5.3 Security Headers - MISSING

  • CSRF protection
  • Security headers middleware
  • Content Security Policy
import NextAuth from "next-auth";
import CredentialsProvider from "next-auth/providers/credentials";
import { BetterSQLite3Adapter } from "@auth/better-sqlite3-adapter";
import db from "./db.js";
import bcrypt from "bcryptjs";
import { z } from "zod";

const loginSchema = z.object({
	email: z.string().email("Invalid email format"),
	password: z.string().min(6, "Password must be at least 6 characters"),
});

export const { handlers, auth, signIn, signOut } = NextAuth({
	adapter: BetterSQLite3Adapter(db),
	session: {
		strategy: "database",
		maxAge: 30 * 24 * 60 * 60, // 30 days
		updateAge: 24 * 60 * 60, // 24 hours
	},
	providers: [
		CredentialsProvider({
			name: "credentials",
			credentials: {
				email: { label: "Email", type: "email" },
				password: { label: "Password", type: "password" },
			},
			async authorize(credentials, req) {
				try {
					// Validate input
					const validatedFields = loginSchema.parse(credentials);

					// Check if user exists and is active
					const user = db
						.prepare(
							`
            SELECT id, email, name, password_hash, role, is_active, 
                   failed_login_attempts, locked_until
            FROM users 
            WHERE email = ? AND is_active = 1
          `
						)
						.get(validatedFields.email);

					if (!user) {
						throw new Error("Invalid credentials");
					}

					// Check if account is locked
					if (user.locked_until && new Date(user.locked_until) > new Date()) {
						throw new Error("Account temporarily locked");
					}

					// Verify password
					const isValidPassword = await bcrypt.compare(
						validatedFields.password,
						user.password_hash
					);

					if (!isValidPassword) {
						// Increment failed attempts
						db.prepare(
							`
              UPDATE users 
              SET failed_login_attempts = failed_login_attempts + 1,
                  locked_until = CASE 
                    WHEN failed_login_attempts >= 4 
                    THEN datetime('now', '+15 minutes')
                    ELSE locked_until 
                  END
              WHERE id = ?
            `
						).run(user.id);

						throw new Error("Invalid credentials");
					}

					// Reset failed attempts and update last login
					db.prepare(
						`
            UPDATE users 
            SET failed_login_attempts = 0, 
                locked_until = NULL,
                last_login = CURRENT_TIMESTAMP
            WHERE id = ?
          `
					).run(user.id);

					// Log successful login
					logAuditEvent(user.id, "LOGIN_SUCCESS", "user", user.id, req);

					return {
						id: user.id,
						email: user.email,
						name: user.name,
						role: user.role,
					};
				} catch (error) {
					console.error("Login error:", error);
					return null;
				}
			},
		}),
	],
	callbacks: {
		async jwt({ token, user, account }) {
			if (user) {
				token.role = user.role;
				token.userId = user.id;
			}
			return token;
		},
		async session({ session, token, user }) {
			if (token) {
				session.user.id = token.userId || token.sub;
				session.user.role = token.role || user?.role;
			}
			return session;
		},
		async signIn({ user, account, profile, email, credentials }) {
			// Additional sign-in logic if needed
			return true;
		},
	},
	pages: {
		signIn: "/auth/signin",
		signOut: "/auth/signout",
		error: "/auth/error",
	},
	events: {
		async signOut({ session, token }) {
			if (session?.user?.id) {
				logAuditEvent(session.user.id, "LOGOUT", "user", session.user.id);
			}
		},
	},
});

// Audit logging helper
function logAuditEvent(userId, action, resourceType, resourceId, req = null) {
	try {
		db.prepare(
			`
      INSERT INTO audit_logs (user_id, action, resource_type, resource_id, ip_address, user_agent)
      VALUES (?, ?, ?, ?, ?, ?)
    `
		).run(
			userId,
			action,
			resourceType,
			resourceId,
			req?.ip || "unknown",
			req?.headers?.["user-agent"] || "unknown"
		);
	} catch (error) {
		console.error("Audit log error:", error);
	}
}

2.2 API Route Handlers

Create src/app/api/auth/[...nextauth]/route.js:

import { handlers } from "@/lib/auth";

export const { GET, POST } = handlers;

Phase 3: Authorization Middleware

3.1 API Protection Middleware

Create src/lib/middleware/auth.js:

import { auth } from "@/lib/auth";
import { NextResponse } from "next/server";
import { z } from "zod";

// Role hierarchy for permission checking
const ROLE_HIERARCHY = {
	admin: 4,
	project_manager: 3,
	user: 2,
	read_only: 1,
};

export function withAuth(handler, options = {}) {
	return async (req, context) => {
		try {
			const session = await auth();

			// Check if user is authenticated
			if (!session?.user) {
				return NextResponse.json(
					{ error: "Authentication required" },
					{ status: 401 }
				);
			}

			// Check if user account is active
			const user = db
				.prepare("SELECT is_active FROM users WHERE id = ?")
				.get(session.user.id);
			if (!user?.is_active) {
				return NextResponse.json(
					{ error: "Account deactivated" },
					{ status: 403 }
				);
			}

			// Check role-based permissions
			if (
				options.requiredRole &&
				!hasPermission(session.user.role, options.requiredRole)
			) {
				logAuditEvent(
					session.user.id,
					"ACCESS_DENIED",
					options.resource || "api",
					req.url
				);
				return NextResponse.json(
					{ error: "Insufficient permissions" },
					{ status: 403 }
				);
			}

			// Check resource-specific permissions
			if (options.checkResourceAccess) {
				const hasAccess = await options.checkResourceAccess(
					session.user,
					context.params
				);
				if (!hasAccess) {
					return NextResponse.json(
						{ error: "Access denied to this resource" },
						{ status: 403 }
					);
				}
			}

			// Validate request body if schema provided
			if (
				options.bodySchema &&
				(req.method === "POST" ||
					req.method === "PUT" ||
					req.method === "PATCH")
			) {
				try {
					const body = await req.json();
					options.bodySchema.parse(body);
				} catch (error) {
					return NextResponse.json(
						{ error: "Invalid request data", details: error.errors },
						{ status: 400 }
					);
				}
			}

			// Add user info to request
			req.user = session.user;
			req.session = session;

			// Call the original handler
			return await handler(req, context);
		} catch (error) {
			console.error("Auth middleware error:", error);
			return NextResponse.json(
				{ error: "Internal server error" },
				{ status: 500 }
			);
		}
	};
}

export function hasPermission(userRole, requiredRole) {
	return ROLE_HIERARCHY[userRole] >= ROLE_HIERARCHY[requiredRole];
}

// Helper for read-only operations
export function withReadAuth(handler) {
	return withAuth(handler, { requiredRole: "read_only" });
}

// Helper for user-level operations
export function withUserAuth(handler) {
	return withAuth(handler, { requiredRole: "user" });
}

// Helper for project manager operations
export function withManagerAuth(handler) {
	return withAuth(handler, { requiredRole: "project_manager" });
}

// Helper for admin operations
export function withAdminAuth(handler) {
	return withAuth(handler, { requiredRole: "admin" });
}

3.2 Client-Side Route Protection

Create src/components/auth/ProtectedRoute.js:

"use client";

import { useSession } from "next-auth/react";
import { useRouter } from "next/navigation";
import { useEffect } from "react";

export function ProtectedRoute({
	children,
	requiredRole = null,
	fallback = null,
}) {
	const { data: session, status } = useSession();
	const router = useRouter();

	useEffect(() => {
		if (status === "loading") return; // Still loading

		if (!session) {
			router.push("/auth/signin");
			return;
		}

		if (requiredRole && !hasPermission(session.user.role, requiredRole)) {
			router.push("/unauthorized");
			return;
		}
	}, [session, status, router, requiredRole]);

	if (status === "loading") {
		return (
			<div className="flex justify-center items-center h-64">Loading...</div>
		);
	}

	if (!session) {
		return fallback || <div>Redirecting to login...</div>;
	}

	if (requiredRole && !hasPermission(session.user.role, requiredRole)) {
		return fallback || <div>Access denied</div>;
	}

	return children;
}

function hasPermission(userRole, requiredRole) {
	const roleHierarchy = {
		admin: 4,
		project_manager: 3,
		user: 2,
		read_only: 1,
	};

	return roleHierarchy[userRole] >= roleHierarchy[requiredRole];
}

Phase 4: User Interface Components

4.1 Authentication Pages

Pages to create:

  • src/app/auth/signin/page.js - Login form
  • src/app/auth/signout/page.js - Logout confirmation
  • src/app/auth/error/page.js - Error handling
  • src/app/unauthorized/page.js - Access denied page

4.2 Navigation Updates

Update src/components/ui/Navigation.js to include:

  • Login/logout buttons
  • User info display
  • Role-based menu items

4.3 User Management Interface

For admin users:

  • User listing and management
  • Role assignment
  • Account activation/deactivation

Phase 5: Security Enhancements

5.1 Input Validation Schemas

Create src/lib/schemas/ with Zod schemas for all API endpoints:

// src/lib/schemas/project.js
import { z } from "zod";

export const createProjectSchema = z.object({
	contract_id: z.number().int().positive(),
	project_name: z.string().min(1).max(255),
	project_number: z.string().min(1).max(50),
	address: z.string().optional(),
	// ... other fields
});

export const updateProjectSchema = createProjectSchema.partial();

5.2 Rate Limiting

Implement rate limiting for sensitive endpoints:

// src/lib/middleware/rateLimit.js
const attempts = new Map();

export function withRateLimit(
	handler,
	options = { maxAttempts: 5, windowMs: 15 * 60 * 1000 }
) {
	return async (req, context) => {
		const key = req.ip || "unknown";
		const now = Date.now();
		const window = attempts.get(key) || {
			count: 0,
			resetTime: now + options.windowMs,
		};

		if (now > window.resetTime) {
			window.count = 1;
			window.resetTime = now + options.windowMs;
		} else {
			window.count++;
		}

		attempts.set(key, window);

		if (window.count > options.maxAttempts) {
			return NextResponse.json({ error: "Too many requests" }, { status: 429 });
		}

		return handler(req, context);
	};
}

Implementation Checklist (Updated Status)

Phase 1: Foundation - COMPLETED

  • Install dependencies (NextAuth.js v5, bcryptjs, zod)
  • Create environment configuration (.env.local)
  • Extend database schema (users, sessions, audit_logs)
  • Create initial admin user script

Phase 2: Authentication - COMPLETED

  • Configure NextAuth.js with credentials provider
  • Create API route handlers (/api/auth/[...nextauth])
  • Implement user management system
  • Test login/logout functionality

Phase 3: Authorization - COMPLETED

  • Implement API middleware (withAuth, role hierarchy)
  • Protect existing API routes (projects, contracts, tasks, notes)
  • Create role-based helper functions
  • Integrate session provider in app layout

🔄 Phase 4: User Interface - IN PROGRESS

  • Create sign-in page with form validation
  • Update navigation component with auth integration
  • Add role-based menu items
  • Create sign-out confirmation page
  • Create error handling page
  • Create unauthorized access page
  • Build admin user management interface

Phase 5: Security Enhancements - NOT STARTED

  • Add input validation schemas to all endpoints
  • Implement rate limiting for sensitive operations
  • Add comprehensive audit logging
  • Create security headers middleware
  • Implement CSRF protection
  • Add password reset functionality

Current Working Features

🔐 Authentication System

  • Login/Logout: Fully functional with NextAuth.js
  • Session Management: JWT-based with 30-day expiration
  • Password Security: bcrypt hashing with salt rounds
  • Account Lockout: 5 failed attempts = 15-minute lockout
  • Role System: 4-tier hierarchy (admin, project_manager, user, read_only)

🛡️ Authorization System

  • API Protection: All major endpoints require authentication
  • Role-Based Access: Different permission levels per endpoint
  • Middleware: Clean abstraction with helper functions
  • Session Validation: Automatic session verification

📱 User Interface

  • Navigation: Context-aware with user info and sign-out
  • Auth Pages: Professional sign-in form with error handling
  • Role Integration: Admin users see additional menu items
  • Responsive: Works across device sizes

🗄️ Database Security

  • User Management: Complete CRUD with proper validation
  • Audit Schema: Ready for comprehensive logging
  • Indexes: Optimized for performance
  • Constraints: Role validation and data integrity

Next Priority Tasks

  1. Complete Auth UI (High Priority)

    • Sign-out confirmation page
    • Unauthorized access page
    • Enhanced error handling
  2. Admin User Management (High Priority)

    • User listing interface
    • Create/edit user forms
    • Role assignment controls
  3. Security Enhancements (Medium Priority)

    • Input validation schemas
    • Rate limiting middleware
    • Comprehensive audit logging
  4. Password Management (Medium Priority)

    • Password reset functionality
    • Password strength requirements
    • Password change interface

Security Best Practices

1. Password Security

  • Minimum 8 characters
  • Require special characters, numbers
  • Hash with bcrypt (cost factor 12+)
  • Implement password history

2. Session Security

  • Secure cookies
  • Session rotation
  • Timeout handling
  • Device tracking

3. API Security

  • Input validation on all endpoints
  • SQL injection prevention (prepared statements)
  • XSS protection
  • CSRF tokens

4. Audit & Monitoring

  • Log all authentication events
  • Monitor failed login attempts
  • Track permission changes
  • Alert on suspicious activity

Testing Status

Completed Tests

  • Authentication Flow: Login/logout working correctly
  • API Protection: All endpoints properly secured
  • Role Validation: Permission levels enforced
  • Session Management: JWT tokens and expiration working
  • Password Security: bcrypt hashing and verification functional
  • Account Lockout: Failed attempt tracking and temporary lockout

🔧 Available Test Scripts

  • test-auth.mjs - Tests API route protection and auth endpoints
  • test-auth-detailed.mjs - Comprehensive authentication flow testing
  • test-complete-auth.mjs - Full system authentication validation
  • test-logged-in-flow.mjs - Authenticated user session testing

Verified Security Features

  • Unauthorized API requests return 401
  • Role-based access control working
  • Session tokens properly validated
  • Password attempts tracked and limited
  • Admin user creation and management functional

Deployment Considerations

1. Environment Variables

  • Use strong, random secrets
  • Different keys per environment
  • Secure secret management

2. Database Security

  • Regular backups
  • Encryption at rest
  • Network security
  • Access logging

3. Application Security

  • HTTPS enforcement
  • Security headers
  • Content Security Policy
  • Regular security updates

Migration Strategy

1. Development Phase

  • Implement on development branch
  • Test thoroughly with sample data
  • Document all changes

2. Staging Deployment

  • Deploy to staging environment
  • Performance testing
  • Security testing
  • User acceptance testing

3. Production Deployment

  • Database backup before migration
  • Gradual rollout
  • Monitor for issues
  • Rollback plan ready

Resources and Documentation

NextAuth.js

Security Libraries

Best Practices


Next Steps: Choose which phase to implement first and create detailed implementation tickets for development.