🔐 Authentication Architecture Guide
🏗️ Architecture Overview
Section titled “🏗️ Architecture Overview”The ERP-Unlocked platform uses a layered authentication architecture that provides consistent security across all applications while maintaining flexibility for different use cases.
Architecture Layers
Section titled “Architecture Layers”┌─────────────────────────────────────────────────────────────────┐│ Application Layer ││ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────────┐ ││ │ Webapp │ │ CRM │ │ Marketing │ ││ │ (Astro App) │ │ (Astro App) │ │ (Astro App) │ ││ └─────────────┘ └─────────────┘ └─────────────────────────┘ │└─────────────────────────────────────────────────────────────────┘┌─────────────────────────────────────────────────────────────────┐│ Middleware Layer ││ ┌─────────────────────────────────────────────────────────────┐ ││ │ Enhanced Shared Middleware │ ││ │ ┌─────────────────┐ ┌─────────────────────────────────┐ │ ││ │ │ Auth Logic │ │ Security Features │ │ ││ │ │ • Route Protection│ │ • CSP Headers │ │ ││ │ │ • Admin Checking │ │ • Security Headers │ │ ││ │ │ • Org Context │ │ • Rate Limiting │ │ ││ │ └─────────────────┘ └─────────────────────────────────┘ │ ││ └─────────────────────────────────────────────────────────────┘ │└─────────────────────────────────────────────────────────────────┘┌─────────────────────────────────────────────────────────────────┐│ Core Auth Package ││ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────────┐ ││ │ Server │ │Organization │ │ Astro │ ││ │ Utils │ │ Utils │ │ Utils │ ││ └─────────────┘ └─────────────┘ └─────────────────────────┘ │└─────────────────────────────────────────────────────────────────┘┌─────────────────────────────────────────────────────────────────┐│ Clerk Authentication ││ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────────┐ ││ │ Users │ │Organizations│ │ Sessions │ ││ │ & Roles │ │ & Roles │ │ & Tokens │ ││ └─────────────┘ └─────────────┘ └─────────────────────────┘ │└─────────────────────────────────────────────────────────────────┘🎯 Available Utilities & When to Use Them
Section titled “🎯 Available Utilities & When to Use Them”1. @repo/auth - Core Authentication Package
Section titled “1. @repo/auth - Core Authentication Package”Purpose: Server-side authentication and organization management Safe For: ✅ Server-side code, API routes, middleware Not For: ❌ Client-side components, Astro pages
import { authenticateRequest, getUserFromSession, isOrganizationAdmin, getCurrentOrganization,} from '@repo/auth';
// Server-side authenticationconst auth = await authenticateRequest(request);const user = await getUserFromSession(auth);
// Organization managementconst isAdmin = await isOrganizationAdmin(auth, orgId);const org = await getCurrentOrganization(auth, orgSlug);2. @repo/auth/middleware - Enhanced Shared Middleware
Section titled “2. @repo/auth/middleware - Enhanced Shared Middleware”Purpose: Configurable authentication middleware for Astro applications Safe For: ✅ Astro middleware, route protection Not For: ❌ API routes, server-side logic
import { createAuthMiddleware } from '@repo/auth/middleware';
const config = { protectedRoutes: ['/dashboard', '/admin'], publicRoutes: ['/', '/sign-in'], adminRoutes: ['/admin'], organizationRequiredRoutes: ['/billing'], organizationOptionalRoutes: ['/dashboard'], enableOrganizationContext: true, signInPath: '/sign-in', dashboardPath: '/dashboard', onboardingPath: '/onboarding/organization',};
export const onRequest = createAuthMiddleware(config);3. @repo/auth/astro - Astro-Specific Utilities
Section titled “3. @repo/auth/astro - Astro-Specific Utilities”Purpose: Authentication utilities for Astro pages, layouts, and components Safe For: ✅ Astro pages, layouts, components Not For: ❌ API routes, server-side logic
import { getUser, requireAdmin } from '@repo/auth/astro';
// In .astro filesconst user = getUser(Astro);const adminUser = requireAdmin(Astro); // Throws if not admin4. BaseAPIHandler - API Route Base Class
Section titled “4. BaseAPIHandler - API Route Base Class”Purpose: Base class for API routes with built-in authentication and authorization Safe For: ✅ API route implementations Not For: ❌ Non-API code, client-side logic
import { BaseAPIHandler } from '@/lib/api/base-handler';
class MyAPIHandler extends BaseAPIHandler { async POST({ locals, request }: Parameters<APIRoute>[0]) { return this.handleRequest(async () => { const { userId } = await this.requireAuth(locals, request); const { userId: adminUserId } = await this.requireAdmin(locals, request);
// Your API logic here return APIResponse.success({ message: 'Success' }); }); }}🔒 Security Considerations
Section titled “🔒 Security Considerations”Authentication Flow
Section titled “Authentication Flow”- Middleware Layer: Route-level protection and user context setup
- API Layer: Server-side authentication enforcement via
BaseAPIHandler - Page Layer: UI-level checks via
@repo/auth/astro(for display only)
Admin Access Control
Section titled “Admin Access Control”- System Admin: Global admin role (
'admin'inuser.publicMetadata.roles) - Organization Admin: Organization-specific admin role (
'org:admin','owner','org:owner') - API Enforcement: All admin checks enforced server-side
- UI Display: Admin UI elements controlled by
@repo/auth/astroutilities
Organization Context
Section titled “Organization Context”- Required Routes: Must have organization context (e.g.,
/billing,/organization) - Optional Routes: Can work with or without organization context (e.g.,
/dashboard,/orders) - Admin Routes: Always require organization context for proper role checking
🚀 Middleware Consolidation & Chaining
Section titled “🚀 Middleware Consolidation & Chaining”Enhanced Shared Middleware
Section titled “Enhanced Shared Middleware”The platform now uses a single, enhanced middleware that supports:
- Basic Apps: Simple protected/public/admin route handling
- Advanced Apps: Organization context, complex route categorization
- Flexible Configuration: Enable/disable features as needed
Middleware Chaining
Section titled “Middleware Chaining”Applications use Astro’s built-in sequence() function to combine multiple middleware functions in a specified order:
- Auth Middleware: Route protection and user context
- Security Middleware: CSP headers, security headers, rate limiting
import { sequence } from 'astro:middleware';
// Use Astro's built-in sequence() function for proper middleware chainingexport const onRequest = sequence(authMiddleware, securityMiddleware);Benefits of using sequence():
- Type Safety: Built-in TypeScript support
- Performance: Optimized execution order
- Idiomatic: Follows Astro best practices
- Maintainable: Clear separation of concerns
- Testable: Each middleware can be tested independently
Configuration Examples
Section titled “Configuration Examples”Webapp (Advanced Features)
Section titled “Webapp (Advanced Features)”const config = { protectedRoutes: ['/dashboard', '/orders', '/erp', '/admin', '/billing', '/organization'], publicRoutes: ['/', '/sign-in', '/sign-up', '/waitlist', '/contact', '/demo'], adminRoutes: ['/admin'], organizationRequiredRoutes: ['/billing', '/organization'], organizationOptionalRoutes: ['/dashboard', '/orders', '/erp'], enableOrganizationContext: true, // Enable advanced org-aware features // CSP configuration for Clerk and other services cspConfig: { clerkDomains: [ 'https://notable-marlin-37.accounts.dev', 'https://notable-marlin-37.clerk.accounts.dev', 'https://rapid-marten-5.accounts.dev', 'https://rapid-marten-5.clerk.accounts.dev', 'https://*.clerk.accounts.dev', // Wildcard for any Clerk instance 'https://*.clerk.com', ], stripeDomains: ['https://api.stripe.com', 'https://*.js.stripe.com', 'https://js.stripe.com'], sentryDomains: [ 'https://*.sentry.io', 'https://js.sentry-cdn.com', 'https://browser.sentry-cdn.com', ], googleDomains: [ 'https://maps.googleapis.com', 'https://fonts.googleapis.com', 'https://fonts.gstatic.com', ], },};CRM (Basic Features)
Section titled “CRM (Basic Features)”const config = { protectedRoutes: ['/dashboard', '/companies', '/contacts', '/tasks'], publicRoutes: ['/', '/sign-in', '/sign-up'], adminRoutes: [], // No admin routes yet enableOrganizationContext: false, // Simple auth only // CSP configuration for Clerk and other services cspConfig: { clerkDomains: [ 'https://notable-marlin-37.accounts.dev', 'https://notable-marlin-37.clerk.accounts.dev', 'https://*.clerk.accounts.dev', // Wildcard for any Clerk instance 'https://*.clerk.com', ], stripeDomains: ['https://api.stripe.com', 'https://*.js.stripe.com', 'https://js.stripe.com'], sentryDomains: [ 'https://*.sentry.io', 'https://js.sentry-cdn.com', 'https://browser.sentry-cdn.com', ], googleDomains: [ 'https://maps.googleapis.com', 'https://fonts.googleapis.com', 'https://fonts.gstatic.com', ], },};CSP Configuration Options
Section titled “CSP Configuration Options”The enhanced shared middleware provides comprehensive CSP configuration for security and service integration:
Available CSP Options
Section titled “Available CSP Options”cspConfig: { clerkDomains?: string[]; // Clerk authentication domains stripeDomains?: string[]; // Stripe payment domains sentryDomains?: string[]; // Sentry error tracking domains googleDomains?: string[]; // Google services domains additionalConnectSrc?: string[]; // Additional connect-src domains additionalScriptSrc?: string[]; // Additional script-src domains additionalFrameSrc?: string[]; // Additional frame-src domains}Default CSP Domains
Section titled “Default CSP Domains”If no CSP configuration is provided, the middleware uses sensible defaults:
- Clerk:
https://*.clerk.accounts.dev,https://*.clerk.com - Stripe:
https://api.stripe.com,https://*.js.stripe.com - Sentry:
https://*.sentry.io,https://js.sentry-cdn.com - Google:
https://maps.googleapis.com,https://fonts.googleapis.com
CSP Header Generation
Section titled “CSP Header Generation”The middleware automatically generates comprehensive CSP headers using the generateCSPHeaders() function:
import { generateCSPHeaders } from '@repo/auth/middleware';
// Generate CSP headers with custom configurationconst cspHeader = generateCSPHeaders(authConfig.cspConfig);response.headers.set('Content-Security-Policy', cspHeader);📋 Common Anti-Patterns to Avoid
Section titled “📋 Common Anti-Patterns to Avoid”❌ Don’t Do This
Section titled “❌ Don’t Do This”// ❌ Direct metadata access (bypasses centralized logic)const isAdmin = user.publicMetadata.roles?.includes('admin');
// ❌ Direct locals access (bypasses middleware)const user = context.locals.user;
// ❌ Client-side admin enforcement (can be bypassed)if (user.role === 'admin') { /* sensitive operation */}✅ Do This Instead
Section titled “✅ Do This Instead”// ✅ Use centralized utilitiesconst isAdmin = await isOrganizationAdmin(auth, orgId);
// ✅ Use middleware-provided contextconst user = getUser(Astro); // From @repo/auth/astro
// ✅ Server-side enforcementconst { userId } = await this.requireAdmin(locals, request);🔄 Migration Guide
Section titled “🔄 Migration Guide”From Old Middleware to Enhanced Shared Middleware
Section titled “From Old Middleware to Enhanced Shared Middleware”- Replace custom middleware logic with
createAuthMiddleware(config) - Configure route categories (protected, public, admin, org-required, org-optional)
- Enable organization context if needed (
enableOrganizationContext: true) - Use middleware chaining for additional security features
From Direct Auth Access to Centralized Utilities
Section titled “From Direct Auth Access to Centralized Utilities”- Replace
context.locals.userwithgetUser(Astro)from@repo/auth/astro - Replace metadata role checks with
requireAdmin(Astro)orisOrganizationAdmin() - Use
BaseAPIHandlerfor all new API routes - Update imports to use
@repo/authpackages
✅ Implementation Checklist
Section titled “✅ Implementation Checklist”For New Features
Section titled “For New Features”- Middleware: Use
createAuthMiddleware()with appropriate config - Middleware Chaining: Use
sequence()fromastro:middlewarefor multiple middleware - API Routes: Extend
BaseAPIHandlerfor authentication - Pages: Use
@repo/auth/astroutilities for user context - Admin Access: Implement via
requireAdmin()in API layer - Organization Context: Configure routes appropriately
For Existing Code
Section titled “For Existing Code”- Audit: Check for direct metadata access or bypass patterns
- Update: Replace with centralized utilities
- Test: Verify authentication and authorization still work
- Document: Update any custom auth logic documentation
🧪 Testing & Verification
Section titled “🧪 Testing & Verification”Test Commands
Section titled “Test Commands”# Test auth packagecd packages/auth && pnpm test
# Test webapp buildpnpm --filter webapp build
# Test CRM buildpnpm --filter crm build
# Test all appspnpm buildVerification Checklist
Section titled “Verification Checklist”- All tests pass in
@repo/authpackage - Webapp builds successfully with new middleware
- CRM builds successfully with new middleware
- No TypeScript errors in authentication code
- Middleware chaining works correctly
- Organization context handling works as expected
Remember: Always use the appropriate authentication layer for your use case. When in doubt, refer to this guide or check existing implementations in the codebase.