Security Overview
CEDIS Pedidos implements a multi-layered security approach:- Supabase Authentication - JWT-based user authentication
- Row Level Security (RLS) - PostgreSQL database-level access control
- Frontend Route Guards - React component-based authorization
- Account Status Validation - Active account requirement
- Role-Based Access Control (RBAC) - Two-tier permission system
Authentication Flow
User Registration Process
Login Flow
- Tokens stored in
localStorageby Supabase client - Automatic refresh before expiration
- Invalidated on logout
Row Level Security (RLS) Policies
All tables have RLS enabled to enforce access control at the database level.Enabling RLS
supabase/schema.sql:106
sucursales Policies
sucursales_select - Read Access
sucursales_select - Read Access
- Any authenticated user can read all branch offices
- Required for dropdowns and branch selection
supabase/schema.sql:113- ✅ All authenticated users: SELECT
- ❌ INSERT/UPDATE/DELETE: No policies (database managed)
users Policies
users_select - Read Own or Admin Reads All
users_select - Read Own or Admin Reads All
- Users can read their own profile
- Admins can read all user profiles
- User profile display
- Admin user management dashboard
supabase/schema.sql:116users_insert - Self Registration Only
users_insert - Self Registration Only
- Users can only insert their own profile (id must match authenticated user ID)
- Prevents privilege escalation
supabase/schema.sql:118users_update - Self Update Only
users_update - Self Update Only
- Users can only update their own profile
- Admin updates handled via service role or functions
supabase/schema.sql:119- ✅ Own profile: SELECT, UPDATE
- ✅ Admins: SELECT all
- ✅ Self registration: INSERT (id=auth.uid())
- ❌ Cross-user modifications: Blocked
materiales Policies
materiales_select - Read Only for Authenticated
materiales_select - Read Only for Authenticated
- All authenticated users can read the material catalog
- Required for order creation and material selection
supabase/schema.sql:122- ✅ All authenticated users: SELECT
- ❌ INSERT/UPDATE/DELETE: No policies (admin via service role)
pedidos Policies
Orders have the most complex policies with role-based and state-based restrictions.pedidos_select - Branch Users See Own, Admins See All
pedidos_select - Branch Users See Own, Admins See All
- Admins can see all orders
- Branch users can only see orders from their assigned branch
- User from “Pachuca I” (sucursal_id=123) only sees pedidos WHERE sucursal_id=123
- Admin sees all pedidos
supabase/schema.sql:125pedidos_insert - Branch Users Create for Own Branch
pedidos_insert - Branch Users Create for Own Branch
- Users can only create orders for their assigned branch
- Prevents creating orders on behalf of other branches
- pedido.sucursal_id must equal user.sucursal_id
supabase/schema.sql:129pedidos_update_sucursal - Draft Orders Only
pedidos_update_sucursal - Draft Orders Only
- Branch users can only update their own branch’s orders
- AND only when estado=‘borrador’ (draft state)
- Once submitted (estado=‘enviado’), users cannot edit
- Drafts are editable by branch users
- Submitted orders are locked for branch users
supabase/schema.sql:132pedidos_update_admin - Admins Update Any Order
pedidos_update_admin - Admins Update Any Order
- Admins can update any order regardless of state or branch
- Used for approving orders (estado=‘borrador’ → ‘aprobado’)
- Used for marking as printed (estado=‘aprobado’ → ‘impreso’)
supabase/schema.sql:138pedidos_delete_sucursal - Delete Draft Orders Only
pedidos_delete_sucursal - Delete Draft Orders Only
- Branch users can delete their own draft orders
- Cannot delete submitted/approved/printed orders
- Must be from user’s branch
supabase/schema.sql:141- ✅ Branch users: SELECT own, INSERT own, UPDATE drafts only, DELETE drafts only
- ✅ Admins: SELECT all, UPDATE all, DELETE not implemented
- ❌ Cross-branch access: Blocked
- ❌ Edit submitted orders (non-admin): Blocked
pedido_detalle Policies
Order line items inherit access rules from parent orders.detalle_select - Follows Parent Order Access
detalle_select - Follows Parent Order Access
- If user can access the parent order, they can access the details
- Reuses pedidos_select logic
supabase/schema.sql:147detalle_insert - Draft Orders, Own Branch
detalle_insert - Draft Orders, Own Branch
- Can only add line items to draft orders
- Order must belong to user’s branch
- Cannot add items to submitted orders
supabase/schema.sql:156detalle_update - Draft Orders, Own Branch
detalle_update - Draft Orders, Own Branch
- Can only update line items in draft orders
- Order must belong to user’s branch
supabase/schema.sql:164detalle_delete - Draft Orders, Own Branch
detalle_delete - Draft Orders, Own Branch
- Can only delete line items from draft orders
- Order must belong to user’s branch
supabase/schema.sql:172Admin Override Policies
Admin Override Policies
- Admins can INSERT/UPDATE/DELETE any order details regardless of state
- Allows admin corrections and adjustments
supabase/schema.sql:180- ✅ Branch users: SELECT parent order’s details, INSERT/UPDATE/DELETE only in drafts
- ✅ Admins: Full access (INSERT/UPDATE/DELETE any state)
- ❌ Edit submitted order details (non-admin): Blocked
solicitudes_acceso Policies
Access request management for user registration workflow.sol_admin_sel - Admins See All Requests
sol_admin_sel - Admins See All Requests
- Admins can view all access requests
- Used for approval dashboard
supabase/add_auth_access_control.sql:32sol_admin_upd - Admins Approve/Reject
sol_admin_upd - Admins Approve/Reject
- Admins can update request status (pendiente → aprobado/rechazado)
- Sets revisado_por and revisado_at fields
supabase/add_auth_access_control.sql:36sol_insert - Anyone Can Request Access
sol_insert - Anyone Can Request Access
- Any authenticated user can create an access request
- Supports self-registration workflow
supabase/add_auth_access_control.sql:40sol_own_sel_2 - View Own Request
sol_own_sel_2 - View Own Request
- Users can view their own access request
- Check application status
supabase/add_auth_access_control.sql:44- ✅ Admins: SELECT all, UPDATE any
- ✅ Any authenticated: INSERT (create request)
- ✅ Own request: SELECT
- ❌ Delete requests: No policy
Frontend Route Guards
ProtectedRoute Component
Implemented insrc/components/ProtectedRoute:
src/App.tsx:38
Account States
Theestado_cuenta field controls account activation:
| Estado | Description | Access |
|---|---|---|
| pendiente | Awaiting admin approval | Cannot login |
| activo | Active account | Full access |
| inactivo | Deactivated by admin | Cannot login |
- Checked during login (AuthContext)
- Checked by ProtectedRoute component
- Cannot be bypassed via API (RLS enforces at DB level)
Superadmin Flag
Thees_superadmin boolean provides elevated privileges:
supabase/add_auth_access_control.sql:49
Current Superadmins:
Use Cases:
- Bypass certain UI restrictions (if implemented)
- System maintenance operations
- Cannot be self-assigned (requires database UPDATE)
Security Best Practices
1. Never Trust Frontend Validation
❌ Bad:2. Use Service Role Sparingly
The Supabase service role key bypasses RLS. Only use it for:- Admin operations in secure backend functions
- Database migrations
- System maintenance scripts
3. Validate estado_cuenta
Always check account status after authentication:4. Audit Trail
Important fields for auditing:pedidos.enviado_at- Submission timestamppedidos.enviado_por- User who submittedsolicitudes_acceso.revisado_por- Admin who approvedsolicitudes_acceso.revisado_at- Approval timestamp
5. Environment Variables
Store credentials securely:Security Checklist
Authentication Security
Authentication Security
- ✅ JWT tokens used for authentication
- ✅ Tokens stored securely in localStorage
- ✅ Automatic token refresh
- ✅ Session invalidation on logout
- ✅ Account status validation (estado_cuenta)
Authorization Security
Authorization Security
Data Protection
Data Protection
- ✅ UNIQUE constraints prevent duplicates
- ✅ Foreign key CASCADE protects referential integrity
- ✅ Check constraints validate enum values
- ✅ NOT NULL constraints prevent invalid states
- ✅ Indexes optimize query performance
Audit & Compliance
Audit & Compliance
- ✅ Timestamps on critical operations (created_at, updated_at)
- ✅ User tracking (enviado_por, revisado_por)
- ✅ Immutable submitted orders (estado != ‘borrador’)
- ✅ Approval workflow (solicitudes_acceso)
Common Security Scenarios
Scenario 1: Branch User Tries to View Another Branch’s Order
Request:Scenario 2: Branch User Tries to Edit Submitted Order
Request:Scenario 3: Admin Views All Orders
Request:Scenario 4: Unauthenticated API Request
Request:Testing Security
Manual RLS Testing
Test policies in Supabase SQL Editor:Automated Testing
Use Supabase test helpers:Future Security Enhancements
Potential Improvements
Potential Improvements
- Audit Logging Table: Log all sensitive operations (order approvals, deletions)
- IP Whitelisting: Restrict admin access to specific IP ranges
- Two-Factor Authentication: Add 2FA for admin accounts
- Password Policies: Enforce strong passwords (handled by Supabase Auth)
- Session Timeouts: Implement automatic logout after inactivity
- Role Hierarchies: Add more granular roles (warehouse_manager, viewer, etc.)
- Field-Level Security: Hide sensitive fields from certain roles
- Rate Limiting: Prevent brute force attacks (via Supabase Dashboard)