Security Architecture

Authentication, authorization, data protection, and security patterns for Smart Shelf.

Security Architecture

This section covers the comprehensive security architecture, authentication patterns, authorization mechanisms, and data protection strategies used in Smart Shelf.

Security Overview

Smart Shelf implements a defense-in-depth security strategy with multiple layers of protection:

Security Philosophy

  • Security by Design: Security considerations integrated from the ground up
  • Principle of Least Privilege: Users and systems have minimal access needed
  • Zero-Trust Architecture: Verify every request regardless of source
  • Defense in Depth: Multiple security layers for comprehensive protection

Security Layers

  • Client-side validation (User Experience)
  • Server-side validation (Security Enforcement)
  • Database-level security (Data Protection)
  • Infrastructure-level security (Network Protection)

Security Architecture Sections

Authentication

Complete authentication system implementation including JWT tokens, session management, and multi-factor authentication support.

Key Topics:

  • Authentication flow and token management
  • Server-side and client-side authentication
  • Session handling and security
  • Password policies and requirements

Data Protection

Comprehensive data protection strategies including encryption, secure storage, and privacy safeguards.

Key Topics:

  • Encryption at rest and in transit
  • Application-level field encryption
  • Secure data handling practices
  • Data backup and recovery security

Authorization & Access Control

Role-based access control (RBAC), permissions management, and authorization guards throughout the application.

Key Topics:

  • Role hierarchy and permissions
  • Component-level authorization guards
  • API route protection
  • Database row-level security policies

Security Monitoring & Auditing

Comprehensive monitoring, audit logging, and threat detection systems for proactive security management.

Key Topics:

  • Audit logging and event tracking
  • Security headers and CSRF protection
  • Rate limiting and abuse prevention
  • Threat detection and incident response

Compliance & Privacy

GDPR compliance, data privacy measures, and regulatory requirements implementation.

Key Topics:

  • GDPR compliance framework
  • Data subject rights implementation
  • Privacy by design principles
  • Data retention and disposal policies

Security Architecture Flow

graph TB
    A[Client Request] --> B[Security Headers]
    B --> C[Rate Limiting]
    C --> D[Authentication]
    D --> E[Authorization]
    E --> F[Data Access]
    F --> G[Audit Logging]
    
    H[Data Protection] --> F
    I[Monitoring] --> G
    J[Compliance] --> H
    
    style A fill:#e1f5fe
    style G fill:#f3e5f5
    style H fill:#fff3e0
    style I fill:#e8f5e8
    style J fill:#fce4ec
// JWT Payload Structure
interface JWTPayload {
  // Standard claims
  sub: string;          // User ID
  iss: string;          // Issuer (Supabase)
  aud: string;          // Audience
  exp: number;          // Expiration timestamp
  iat: number;          // Issued at timestamp
  
  // Custom claims
  email: string;        // User email
  role: string;         // User role
  warehouse_id?: string; // Default warehouse
  permissions: string[]; // User permissions
  session_id: string;   // Session identifier
}

Authentication Implementation

Server-Side Authentication

// lib/auth/server.ts
import { createServerComponentClient } from '@supabase/auth-helpers-nextjs';
import { cookies } from 'next/headers';
import { redirect } from 'next/navigation';

export async function getCurrentUser() {
  const supabase = createServerComponentClient({ cookies });
  
  try {
    const { data: { session }, error } = await supabase.auth.getSession();
    
    if (error || !session) {
      return null;
    }
    
    // Get user profile with permissions
    const { data: profile } = await supabase
      .from('user_profiles')
      .select('*, user_roles(role, permissions)')
      .eq('id', session.user.id)
      .single();
    
    return {
      id: session.user.id,
      email: session.user.email,
      ...profile,
    };
  } catch (error) {
    console.error('Authentication error:', error);
    return null;
  }
}

export async function requireAuth() {
  const user = await getCurrentUser();
  
  if (!user) {
    redirect('/auth/login');
  }
  
  return user;
}

Client-Side Authentication

// lib/auth/client.ts
import { createClientComponentClient } from '@supabase/auth-helpers-nextjs';
import { useRouter } from 'next/navigation';

export function useAuth() {
  const supabase = createClientComponentClient();
  const router = useRouter();
  
  const signIn = async (email: string, password: string) => {
    const { data, error } = await supabase.auth.signInWithPassword({
      email,
      password,
    });
    
    if (error) {
      throw new Error(error.message);
    }
    
    router.push('/dashboard');
    return data;
  };
  
  const signOut = async () => {
    await supabase.auth.signOut();
    router.push('/auth/login');
  };
  
  const signUp = async (email: string, password: string, userData: any) => {
    const { data, error } = await supabase.auth.signUp({
      email,
      password,
      options: {
        data: userData,
      },
    });
    
    if (error) {
      throw new Error(error.message);
    }
    
    return data;
  };
  
  return {
    signIn,
    signOut,
    signUp,
  };
}

Authorization Architecture

Role-Based Access Control (RBAC)

// lib/auth/roles.ts
export enum UserRole {
  ADMIN = 'admin',
  MANAGER = 'manager',
  STAFF = 'staff',
  READONLY = 'readonly',
}

export const ROLE_HIERARCHY = {
  [UserRole.ADMIN]: 4,
  [UserRole.MANAGER]: 3,
  [UserRole.STAFF]: 2,
  [UserRole.READONLY]: 1,
};

export const PERMISSIONS = {
  // Product Management
  'products:read': [UserRole.ADMIN, UserRole.MANAGER, UserRole.STAFF, UserRole.READONLY],
  'products:create': [UserRole.ADMIN, UserRole.MANAGER],
  'products:update': [UserRole.ADMIN, UserRole.MANAGER],
  'products:delete': [UserRole.ADMIN],
  
  // Inventory Management
  'inventory:read': [UserRole.ADMIN, UserRole.MANAGER, UserRole.STAFF, UserRole.READONLY],
  'inventory:adjust': [UserRole.ADMIN, UserRole.MANAGER],
  'inventory:transfer': [UserRole.ADMIN, UserRole.MANAGER],
  'inventory:count': [UserRole.ADMIN, UserRole.MANAGER, UserRole.STAFF],
  
  // Order Management
  'orders:read': [UserRole.ADMIN, UserRole.MANAGER, UserRole.STAFF, UserRole.READONLY],
  'orders:create': [UserRole.ADMIN, UserRole.MANAGER, UserRole.STAFF],
  'orders:update': [UserRole.ADMIN, UserRole.MANAGER, UserRole.STAFF],
  'orders:approve': [UserRole.ADMIN, UserRole.MANAGER],
  'orders:cancel': [UserRole.ADMIN, UserRole.MANAGER],
  
  // Financial
  'financial:read': [UserRole.ADMIN, UserRole.MANAGER, UserRole.READONLY],
  'financial:reports': [UserRole.ADMIN, UserRole.MANAGER],
  
  // User Management
  'users:read': [UserRole.ADMIN],
  'users:create': [UserRole.ADMIN],
  'users:update': [UserRole.ADMIN],
  'users:delete': [UserRole.ADMIN],
  
  // System Administration
  'system:settings': [UserRole.ADMIN],
  'system:backup': [UserRole.ADMIN],
  'system:audit': [UserRole.ADMIN],
} as const;

export function hasPermission(userRole: UserRole, permission: string): boolean {
  const allowedRoles = PERMISSIONS[permission as keyof typeof PERMISSIONS];
  return allowedRoles?.includes(userRole) ?? false;
}

export function requirePermission(user: User, permission: string): void {
  if (!hasPermission(user.role, permission)) {
    throw new Error(`Access denied: ${permission} permission required`);
  }
}

export function hasHigherRole(userRole: UserRole, targetRole: UserRole): boolean {
  return ROLE_HIERARCHY[userRole] > ROLE_HIERARCHY[targetRole];
}

Authorization Guards

Component-Level Authorization

// components/auth/role-guard.tsx
interface RoleGuardProps {
  allowedRoles: UserRole[];
  children: React.ReactNode;
  fallback?: React.ReactNode;
}

export function RoleGuard({ allowedRoles, children, fallback }: RoleGuardProps) {
  const { user } = useCurrentUser();
  
  if (!user || !allowedRoles.includes(user.role)) {
    return fallback || <UnauthorizedMessage />;
  }
  
  return <>{children}</>;
}

// Usage
<RoleGuard allowedRoles={[UserRole.ADMIN, UserRole.MANAGER]}>
  <AdminPanel />
</RoleGuard>

Permission-Based Guards

// components/auth/permission-guard.tsx
interface PermissionGuardProps {
  permission: string;
  children: React.ReactNode;
  fallback?: React.ReactNode;
}

export function PermissionGuard({ permission, children, fallback }: PermissionGuardProps) {
  const { user } = useCurrentUser();
  
  if (!user || !hasPermission(user.role, permission)) {
    return fallback || null;
  }
  
  return <>{children}</>;
}

// Usage
<PermissionGuard permission="products:create">
  <CreateProductButton />
</PermissionGuard>

API Route Authorization

// lib/auth/api-auth.ts
export function withAuth(
  handler: (req: NextRequest, user: User) => Promise<NextResponse>,
  requiredPermission?: string
) {
  return async function(req: NextRequest) {
    try {
      // Validate authentication
      const user = await validateAuth(req);
      
      // Check permission if required
      if (requiredPermission) {
        requirePermission(user, requiredPermission);
      }
      
      return handler(req, user);
      
    } catch (error) {
      if (error.message.includes('token')) {
        return NextResponse.json(
          { success: false, error: { code: 'UNAUTHORIZED', message: 'Invalid token' } },
          { status: 401 }
        );
      }
      
      if (error.message.includes('Access denied')) {
        return NextResponse.json(
          { success: false, error: { code: 'FORBIDDEN', message: error.message } },
          { status: 403 }
        );
      }
      
      throw error;
    }
  };
}

// Usage
export const GET = withAuth(async (req, user) => {
  // Handler with authenticated user
}, 'products:read');

Database Security (Row Level Security)

RLS Policy Patterns

User-Based Data Isolation

-- Users can only access their own profile
CREATE POLICY "user_profile_isolation" ON user_profiles
  FOR ALL USING (
    auth.uid() = id
  );

-- Users can only view profiles in their organization
CREATE POLICY "organization_profile_access" ON user_profiles
  FOR SELECT USING (
    EXISTS (
      SELECT 1 FROM user_profiles up
      WHERE up.id = auth.uid()
      AND up.organization_id = user_profiles.organization_id
    )
  );

Role-Based Data Access

-- Admins can access all data
CREATE POLICY "admin_full_access" ON products
  FOR ALL USING (
    EXISTS (
      SELECT 1 FROM user_profiles
      WHERE id = auth.uid() AND role = 'admin'
    )
  );

-- Managers can access data in their warehouse
CREATE POLICY "manager_warehouse_access" ON inventory
  FOR ALL USING (
    EXISTS (
      SELECT 1 FROM user_profiles
      WHERE id = auth.uid() 
      AND role IN ('admin', 'manager')
      AND (warehouse_id = inventory.warehouse_id OR role = 'admin')
    )
  );

-- Staff can only read data in their warehouse
CREATE POLICY "staff_warehouse_read" ON inventory
  FOR SELECT USING (
    EXISTS (
      SELECT 1 FROM user_profiles
      WHERE id = auth.uid()
      AND warehouse_id = inventory.warehouse_id
    )
  );

Time-Based Access Control

-- Users can only modify recent records
CREATE POLICY "recent_modifications_only" ON stock_movements
  FOR UPDATE USING (
    created_at > NOW() - INTERVAL '24 hours'
    AND created_by = auth.uid()
  );

-- Prevent modification of finalized orders
CREATE POLICY "no_finalized_order_changes" ON sales_orders
  FOR UPDATE USING (
    status NOT IN ('shipped', 'delivered', 'cancelled')
  );

Data Masking and Field-Level Security

-- Hide sensitive customer data from staff
CREATE POLICY "customer_data_privacy" ON customers
  FOR SELECT USING (
    CASE 
      WHEN EXISTS (
        SELECT 1 FROM user_profiles 
        WHERE id = auth.uid() AND role IN ('admin', 'manager')
      ) THEN true
      ELSE false
    END
  );

-- Create a view with masked data for staff
CREATE OR REPLACE VIEW customer_summary AS
SELECT 
  id,
  name,
  CASE 
    WHEN EXISTS (
      SELECT 1 FROM user_profiles 
      WHERE id = auth.uid() AND role IN ('admin', 'manager')
    ) THEN email
    ELSE REGEXP_REPLACE(email, '(.{2}).*(@.*)', '\1***\2')
  END as email,
  city,
  country,
  is_active
FROM customers;

Data Protection

Data Encryption

Encryption at Rest

  • Database: Supabase provides AES-256 encryption for all data at rest
  • File Storage: All uploaded files encrypted using industry-standard encryption
  • Backups: Encrypted backups stored in multiple geographic locations

Encryption in Transit

  • HTTPS/TLS: All client-server communication encrypted with TLS 1.3
  • Database Connections: SSL/TLS encryption for all database connections
  • API Communications: End-to-end encryption for all API calls

Application-Level Encryption

// lib/encryption/field-encryption.ts
import { createCipher, createDecipher } from 'crypto';

const ENCRYPTION_KEY = process.env.FIELD_ENCRYPTION_KEY!;
const ALGORITHM = 'aes-256-gcm';

export function encryptField(text: string): string {
  try {
    const iv = crypto.randomBytes(16);
    const cipher = createCipher(ALGORITHM, ENCRYPTION_KEY);
    cipher.setAAD(Buffer.from('additional-auth-data'));
    
    let encrypted = cipher.update(text, 'utf8', 'hex');
    encrypted += cipher.final('hex');
    
    const authTag = cipher.getAuthTag();
    
    return `${iv.toString('hex')}:${authTag.toString('hex')}:${encrypted}`;
  } catch (error) {
    throw new Error('Encryption failed');
  }
}

export function decryptField(encryptedText: string): string {
  try {
    const [ivHex, authTagHex, encrypted] = encryptedText.split(':');
    
    const iv = Buffer.from(ivHex, 'hex');
    const authTag = Buffer.from(authTagHex, 'hex');
    
    const decipher = createDecipher(ALGORITHM, ENCRYPTION_KEY);
    decipher.setAAD(Buffer.from('additional-auth-data'));
    decipher.setAuthTag(authTag);
    
    let decrypted = decipher.update(encrypted, 'hex', 'utf8');
    decrypted += decipher.final('utf8');
    
    return decrypted;
  } catch (error) {
    throw new Error('Decryption failed');
  }
}

// Usage in database models
export async function createCustomer(customerData: CustomerInput) {
  const encryptedData = {
    ...customerData,
    // Encrypt sensitive fields
    email: encryptField(customerData.email),
    phone: encryptField(customerData.phone),
    taxId: customerData.taxId ? encryptField(customerData.taxId) : null,
  };
  
  return supabase.from('customers').insert(encryptedData);
}

Data Privacy and GDPR Compliance

Personal Data Handling

// lib/privacy/gdpr.ts
export interface PersonalDataField {
  table: string;
  field: string;
  category: 'identity' | 'contact' | 'financial' | 'behavioral';
  retention: number; // days
}

export const PERSONAL_DATA_FIELDS: PersonalDataField[] = [
  { table: 'user_profiles', field: 'full_name', category: 'identity', retention: 2555 }, // 7 years
  { table: 'user_profiles', field: 'email', category: 'contact', retention: 2555 },
  { table: 'customers', field: 'email', category: 'contact', retention: 2555 },
  { table: 'customers', field: 'phone', category: 'contact', retention: 2555 },
  { table: 'audit_logs', field: 'user_agent', category: 'behavioral', retention: 365 }, // 1 year
];

export async function anonymizeUserData(userId: string): Promise<void> {
  const supabase = createServiceRoleClient();
  
  try {
    // Start transaction
    await supabase.rpc('begin_transaction');
    
    // Anonymize user profile
    await supabase
      .from('user_profiles')
      .update({
        full_name: 'Anonymous User',
        email: `anonymous-${userId}@deleted.local`,
        avatar_url: null,
        is_active: false,
        anonymized_at: new Date().toISOString(),
      })
      .eq('id', userId);
    
    // Anonymize related customer data if exists
    await supabase
      .from('customers')
      .update({
        name: 'Anonymous Customer',
        email: `anonymous-customer-${userId}@deleted.local`,
        phone: null,
        contact_person: 'Anonymous',
      })
      .eq('created_by', userId);
    
    // Keep audit trail but remove identifying information
    await supabase
      .from('audit_logs')
      .update({
        user_agent: 'Anonymous',
        ip_address: '0.0.0.0',
        anonymized: true,
      })
      .eq('user_id', userId);
    
    await supabase.rpc('commit_transaction');
    
  } catch (error) {
    await supabase.rpc('rollback_transaction');
    throw new Error('Failed to anonymize user data');
  }
}

export async function exportUserData(userId: string): Promise<any> {
  const supabase = createServiceRoleClient();
  
  // Export all personal data for GDPR data portability
  const [profile, orders, activities] = await Promise.all([
    supabase.from('user_profiles').select('*').eq('id', userId).single(),
    supabase.from('sales_orders').select('*').eq('created_by', userId),
    supabase.from('audit_logs').select('*').eq('user_id', userId).order('created_at', { ascending: false }).limit(1000),
  ]);
  
  return {
    personal_data: {
      profile: profile.data,
      orders: orders.data,
      activities: activities.data,
    },
    export_date: new Date().toISOString(),
    retention_policy: 'Data will be retained according to our privacy policy',
  };
}

Security Monitoring and Auditing

Audit Logging

// lib/audit/logger.ts
export interface AuditEvent {
  action: string;
  resource: string;
  resourceId?: string;
  userId: string;
  ipAddress?: string;
  userAgent?: string;
  details?: any;
  timestamp: Date;
}

export async function logAuditEvent(event: AuditEvent): Promise<void> {
  const supabase = createServiceRoleClient();
  
  try {
    await supabase.from('audit_logs').insert({
      action: event.action,
      resource: event.resource,
      resource_id: event.resourceId,
      user_id: event.userId,
      ip_address: event.ipAddress,
      user_agent: event.userAgent,
      details: event.details,
      created_at: event.timestamp.toISOString(),
    });
  } catch (error) {
    // Log to external service if database is unavailable
    console.error('Audit logging failed:', error);
  }
}

// Middleware for automatic audit logging
export function withAuditLog(action: string, resource: string) {
  return function(handler: (req: NextRequest, user: User) => Promise<NextResponse>) {
    return async function(req: NextRequest) {
      const user = await validateAuth(req);
      
      try {
        const response = await handler(req, user);
        
        // Log successful action
        await logAuditEvent({
          action,
          resource,
          userId: user.id,
          ipAddress: req.headers.get('x-forwarded-for') || req.ip,
          userAgent: req.headers.get('user-agent'),
          timestamp: new Date(),
        });
        
        return response;
        
      } catch (error) {
        // Log failed action
        await logAuditEvent({
          action: `${action}_failed`,
          resource,
          userId: user.id,
          ipAddress: req.headers.get('x-forwarded-for') || req.ip,
          userAgent: req.headers.get('user-agent'),
          details: { error: error.message },
          timestamp: new Date(),
        });
        
        throw error;
      }
    };
  };
}

Security Headers and CSRF Protection

// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

export function middleware(request: NextRequest) {
  const response = NextResponse.next();
  
  // Security Headers
  response.headers.set('X-Frame-Options', 'DENY');
  response.headers.set('X-Content-Type-Options', 'nosniff');
  response.headers.set('Referrer-Policy', 'strict-origin-when-cross-origin');
  response.headers.set('X-XSS-Protection', '1; mode=block');
  
  // Content Security Policy
  const csp = [
    "default-src 'self'",
    "script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdn.jsdelivr.net",
    "style-src 'self' 'unsafe-inline' https://fonts.googleapis.com",
    "font-src 'self' https://fonts.gstatic.com",
    "img-src 'self' data: https:",
    "connect-src 'self' https://*.supabase.co wss://*.supabase.co",
    "object-src 'none'",
    "base-uri 'self'",
    "form-action 'self'",
    "frame-ancestors 'none'",
  ].join('; ');
  
  response.headers.set('Content-Security-Policy', csp);
  
  // CSRF Protection for state-changing requests
  if (['POST', 'PUT', 'DELETE', 'PATCH'].includes(request.method)) {
    const origin = request.headers.get('origin');
    const host = request.headers.get('host');
    
    if (!origin || !host || !origin.includes(host)) {
      return NextResponse.json(
        { error: 'Invalid origin' },
        { status: 403 }
      );
    }
  }
  
  return response;
}

export const config = {
  matcher: [
    '/((?!api/auth|_next/static|_next/image|favicon.ico).*)',
  ],
};

Security Best Practices Checklist

Development Security

  • All user inputs validated and sanitized
  • SQL injection prevention (parameterized queries)
  • XSS prevention (output encoding)
  • CSRF protection implemented
  • Secure session management
  • Password complexity requirements
  • Rate limiting on API endpoints
  • Error messages don't leak sensitive information

Infrastructure Security

  • HTTPS enforced for all communications
  • Security headers implemented
  • Database connections encrypted
  • Regular security updates applied
  • Environment variables secured
  • Secrets management implemented
  • Network access controls configured
  • Regular security audits performed

Data Security

  • Data encryption at rest and in transit
  • Regular backups with encryption
  • Data retention policies implemented
  • GDPR compliance measures
  • Access logging and monitoring
  • Row-level security policies
  • Field-level encryption for sensitive data
  • Secure data disposal procedures

This security architecture provides comprehensive protection for Smart Shelf while maintaining usability and performance. Regular security reviews and updates ensure ongoing protection against evolving threats.