puffin-app/lib/admin/auth.ts
Matt 683a65c1fd
All checks were successful
Build and Push Docker Images / docker (push) Successful in 2m15s
Implement Modern Maritime admin panel design with Monaco background
🎨 Complete UI redesign of admin panel with professional color scheme:

## New Modern Maritime Color Palette
- Deep Sea Blue (#1D2939) - Sidebar background
- Sail White (#F8F9FA) - Main background
- Maritime Teal (#008B8B) - Primary accent
- Sea Green (#1E8449) - Success/environmental theme
- Muted Gold (#D68910) - Revenue highlights
- Royal Purple (#884EA0) - Brand accent
- Off-White (#EAECEF) - Text on dark backgrounds

## Admin Panel Features
-  JWT-based authentication system
-  Protected routes with middleware
-  Elegant sidebar navigation with Puffin logo
-  Dashboard with stat cards (Orders, CO₂, Revenue, Fulfillment)
-  Monaco harbor image background on login page
-  Responsive glassmorphism design
-  WCAG AA contrast compliance

## New Files
- app/admin/ - Admin pages (login, dashboard, orders)
- app/api/admin/ - Auth API routes (login, logout, verify)
- components/admin/ - AdminSidebar component
- lib/auth.ts - JWT authentication utilities
- public/monaco_high_res.jpg - Luxury background image

## Updated
- tailwind.config.js - Custom maritime color palette
- package.json - Added jsonwebtoken dependency
- app/layout.tsx - RootLayoutClient integration

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 09:35:43 +01:00

77 lines
1.8 KiB
TypeScript

import jwt from 'jsonwebtoken';
const JWT_SECRET = process.env.JWT_SECRET || 'fallback-secret-key';
const TOKEN_EXPIRY = '24h'; // Token expires in 24 hours
export interface AdminUser {
username: string;
isAdmin: true;
}
export interface JWTPayload extends AdminUser {
iat: number;
exp: number;
}
/**
* Verify admin credentials against environment variables
*/
export function verifyCredentials(username: string, password: string): boolean {
const adminUsername = process.env.ADMIN_USERNAME;
const adminPassword = process.env.ADMIN_PASSWORD;
if (!adminUsername || !adminPassword) {
console.error('Admin credentials not configured in environment variables');
return false;
}
return username === adminUsername && password === adminPassword;
}
/**
* Generate JWT token for authenticated admin
*/
export function generateToken(user: AdminUser): string {
return jwt.sign(user, JWT_SECRET, {
expiresIn: TOKEN_EXPIRY,
});
}
/**
* Verify and decode JWT token
* Returns the decoded payload or null if invalid
*/
export function verifyToken(token: string): JWTPayload | null {
try {
const decoded = jwt.verify(token, JWT_SECRET) as JWTPayload;
return decoded;
} catch (error) {
console.error('JWT verification failed:', error);
return null;
}
}
/**
* Extract token from Authorization header
* Supports both "Bearer token" and plain token formats
*/
export function extractToken(authHeader: string | null): string | null {
if (!authHeader) return null;
if (authHeader.startsWith('Bearer ')) {
return authHeader.substring(7);
}
return authHeader;
}
/**
* Check if user is authenticated admin
*/
export function isAuthenticated(token: string | null): boolean {
if (!token) return false;
const payload = verifyToken(token);
return payload !== null && payload.isAdmin === true;
}