UnlockOS Developers
← Back to blog
🛡️

Building Trust Through Production Logging & Auth Hardening

Dec 29, 2025Jan 4, 2026
7 min
45 commits
Depth 8/10
securityauthenticationloggingerror-handlingproduction-hardening

Building Trust Through Production Logging & Authentication Hardening

In security-critical systems like smart lock management, trust is built through meticulous attention to operational visibility and authentication robustness. Recent improvements to our UnlockOS SDK demonstrate key patterns for hardening production systems while maintaining developer experience.

Environment-Aware Logging Strategy

Production systems require different logging approaches than development environments. Implementing environment-specific log levels prevents information leakage while maintaining operational visibility:

interface LogConfig {
  level: 'debug' | 'info' | 'warn' | 'error';
  sensitiveFields: string[];
  maxLogSize: number;
}

class SecureLogger {
  private config: LogConfig;
  
  constructor(environment: 'development' | 'staging' | 'production') {
    this.config = {
      level: environment === 'production' ? 'warn' : 'debug',
      sensitiveFields: ['password', 'token', 'key', 'secret'],
      maxLogSize: environment === 'production' ? 1000 : 5000
    };
  }
  
  log(level: string, message: string, data?: any) {
    if (this.shouldLog(level)) {
      const sanitized = this.sanitizeData(data);
      console[level](message, sanitized);
    }
  }
  
  private sanitizeData(data: any): any {
    if (!data) return data;
    
    const sanitized = { ...data };
    this.config.sensitiveFields.forEach(field => {
      if (sanitized[field]) {
        sanitized[field] = '[REDACTED]';
      }
    });
    return sanitized;
  }
}

OAuth State Management & Re-authentication Prevention

Authentication flows in smart lock systems must be bulletproof. A critical improvement involved preventing unintended re-authentication after OAuth callbacks:

class AuthenticationManager {
  private oauthState: Map<string, {
    timestamp: number;
    used: boolean;
    redirectUrl: string;
  }> = new Map();
  
  async handleOAuthCallback(code: string, state: string): Promise<void> {
    const stateData = this.oauthState.get(state);
    
    // Prevent replay attacks and duplicate processing
    if (!stateData || stateData.used || 
        Date.now() - stateData.timestamp > 300000) { // 5 min expiry
      throw new Error('Invalid or expired OAuth state');
    }
    
    // Mark state as used immediately
    stateData.used = true;
    this.oauthState.set(state, stateData);
    
    try {
      await this.exchangeCodeForToken(code);
      // Prevent main app from triggering re-authentication
      this.clearAuthenticationTriggers();
    } catch (error) {
      this.logAuthenticationFailure(error, { state, timestamp: Date.now() });
      throw error;
    }
  }
  
  private clearAuthenticationTriggers(): void {
    // Clear any pending authentication requests
    sessionStorage.removeItem('pending_auth');
    localStorage.removeItem('auth_redirect');
  }
}

Feature Removal as Security Hardening

Removing features can be as important as adding them. The removal of "guest mode" demonstrates how reducing attack surface improves security posture:

// Before: Complex access control with guest mode
interface AccessControl {
  userType: 'admin' | 'host' | 'guest';
  permissions: Permission[];
  guestLimitations?: GuestLimitation[];
}

// After: Simplified, more secure access control
interface AccessControl {
  userType: 'admin' | 'host';
  permissions: Permission[];
  authenticationRequired: true;
}

class SecurityAudit {
  static validateAccess(user: AuthenticatedUser, resource: Resource): boolean {
    // No guest mode = no unauthenticated access paths
    if (!user.isAuthenticated) {
      this.logUnauthorizedAccess(user.id, resource.id);
      return false;
    }
    
    return this.checkPermissions(user.permissions, resource.requiredPermissions);
  }
}

Row-Level Security (RLS) Policy Hardening

Database security through Row-Level Security policies ensures data isolation even if application-level checks fail:

-- Secure role permission access
CREATE POLICY "role_permission_details_select" ON role_permission_details
FOR SELECT USING (
  EXISTS (
    SELECT 1 FROM user_organization_roles uor
    WHERE uor.user_id = auth.uid()
    AND uor.organization_id = role_permission_details.organization_id
    AND uor.role IN ('admin', 'manager')
  )
);

-- Audit trail for policy violations
CREATE OR REPLACE FUNCTION log_rls_violation()
RETURNS TRIGGER AS $$
BEGIN
  INSERT INTO security_audit_log (user_id, table_name, action, timestamp)
  VALUES (auth.uid(), TG_TABLE_NAME, TG_OP, NOW());
  RETURN NULL;
END;
$$ LANGUAGE plpgsql;

Production-Ready Error Handling

Robust error handling prevents information leakage while maintaining operational visibility:

class ProductionErrorHandler {
  static handlePaymentError(error: unknown, context: PaymentContext): PaymentResult {
    const errorId = this.generateErrorId();
    
    // Log detailed error internally
    logger.error('Payment processing failed', {
      errorId,
      error: error instanceof Error ? error.message : 'Unknown error',
      stack: error instanceof Error ? error.stack : undefined,
      context: this.sanitizeContext(context)
    });
    
    // Return sanitized error to client
    return {
      success: false,
      errorId,
      message: this.getPublicErrorMessage(error),
      retryable: this.isRetryable(error)
    };
  }
  
  private static getPublicErrorMessage(error: unknown): string {
    // Never expose internal error details
    if (error instanceof ValidationError) {
      return error.publicMessage;
    }
    return 'An error occurred. Please contact support with error ID.';
  }
}

Capacity Management & System Limits

Implementing capacity limits prevents system abuse and ensures fair resource allocation:

interface CapacityConfig {
  maxOccupancy: number;
  warningThreshold: number; // 80% of max
  blockNewCheckins: boolean;
}

class OccupancyManager {
  async validateCheckIn(facilityId: string): Promise<CheckInValidation> {
    const current = await this.getCurrentOccupancy(facilityId);
    const config = await this.getCapacityConfig(facilityId);
    
    const congestionRate = (current / config.maxOccupancy) * 100;
    
    if (config.blockNewCheckins && current >= config.maxOccupancy) {
      this.logCapacityViolation(facilityId, current, config.maxOccupancy);
      return {
        allowed: false,
        reason: 'CAPACITY_EXCEEDED',
        congestionRate
      };
    }
    
    return {
      allowed: true,
      congestionRate,
      warning: congestionRate > 80
    };
  }
}

Summary

Building trust in security-critical systems requires:

  1. Layered Logging: Environment-specific log levels with sensitive data sanitization
  2. Authentication Hardening: Proper state management and replay attack prevention
  3. Attack Surface Reduction: Removing unnecessary features like guest modes
  4. Database Security: Row-level security policies as defense in depth
  5. Production Error Handling: Internal visibility without information leakage
  6. System Limits: Capacity management to prevent abuse

These patterns ensure that security is not just a feature, but a fundamental characteristic of the system architecture.

Key Insights

1
Security

Environment-Aware Logging

Different logging strategies for development vs production prevent information leakage while maintaining operational visibility

2
Authentication

OAuth State Management

Proper state tracking and replay prevention in OAuth flows prevents authentication bypasses and duplicate processing

3
Security

Feature Removal for Hardening

Removing guest mode reduces attack surface and eliminates unauthenticated access paths

4
Database Security

Row-Level Security Policies

Database-level access controls provide defense in depth even when application-level checks fail