General

BaaS Security Architecture Guide

Architectural patterns for securing backend-as-a-service applications

Last updated 2026-01-15

The BaaS Security Challenge

Backend-as-a-Service platforms like Supabase and Firebase fundamentally change the security model of web and mobile applications. In a traditional architecture, a server-side application mediates all access to the database and external services. With BaaS, your client application communicates directly with the database, authentication service, and storage. The security boundary shifts from application code to configuration.

Traditional vs. BaaS Security Models

Traditional Architecture

Client --> Server Application --> Database
           (validates,          (no direct
            authorizes,          client access)
            sanitizes)

Security is enforced in the server-side application layer. The database is not exposed to the internet.

BaaS Architecture

Client --> BaaS API (PostgREST, Firestore) --> Database
           (validates JWT,                     (RLS/Security Rules
            applies policies)                   enforce access)

Security is enforced by the BaaS platform through declarative rules and policies. The database is directly accessible via APIs.

Core Security Principles for BaaS

1. Assume the Client Is Compromised

Every piece of client-side code, every API key, every configuration value shipped with your app is accessible to attackers. Design your security model with this assumption.

What the attacker knows:
- Your Supabase URL and anon key
- Your Firebase config (API key, project ID)
- Your API endpoints and request formats
- Your client-side business logic

What protects you:
- RLS policies / Security Rules
- Server-side validation in Edge Functions / Cloud Functions
- Properly configured authentication

2. Defense in Depth

Never rely on a single security control. Layer your defenses:

Layer 1: Authentication (who is the user?)
Layer 2: Authorization policies (RLS / Security Rules)
Layer 3: Input validation (Edge Functions / Cloud Functions)
Layer 4: Rate limiting
Layer 5: Monitoring and alerting
Layer 6: Encrypted data at rest and in transit

3. Least Privilege

Grant the minimum permissions necessary:

-- Supabase: Grant only what's needed
REVOKE ALL ON public.orders FROM anon;
GRANT SELECT ON public.orders TO authenticated;

-- Policies further restrict to user's own data
CREATE POLICY "Users see own orders"
  ON public.orders FOR SELECT
  USING (auth.uid() = user_id);
// Firebase: Restrict to exact needs
match /orders/{orderId} {
  allow read: if request.auth != null
    && resource.data.userId == request.auth.uid;
  allow create: if request.auth != null
    && request.resource.data.userId == request.auth.uid;
  // No update or delete allowed
}

Secure Architecture Patterns

Pattern 1: Client-Direct with Policies

The simplest pattern. The client accesses the database directly, protected by policies:

Client --[JWT]--> PostgREST/Firestore --[RLS/Rules]--> Data

When to use: Simple CRUD applications, user profile management, personal data.

Requirements: Comprehensive RLS policies or security rules on every table/collection.

Pattern 2: Edge Function Gateway

Sensitive operations go through a server-side function:

Client --[JWT]--> Edge/Cloud Function --[service key]--> Database
                  (validates, processes,
                   applies business logic)

When to use: Complex business logic, multi-step operations, interactions with external APIs, operations requiring the service role key.

Example: Payment processing, scan execution, report generation.

Pattern 3: Hybrid

Combine direct access for simple reads with function gateways for writes and sensitive operations:

Reads:   Client --[JWT]--> PostgREST --[RLS]--> Data
Writes:  Client --[JWT]--> Edge Function --[service key + validation]--> Data

This is the most common pattern in production BaaS applications and provides a good balance of performance and security.

Authentication Architecture

JWT Lifecycle

1. User signs in --> BaaS issues JWT (access_token + refresh_token)
2. Client stores tokens securely (httpOnly cookies preferred)
3. Client includes JWT in every request
4. BaaS validates JWT and applies role-based access
5. Token expires --> Client uses refresh_token to get new JWT
6. User signs out --> Refresh token revoked

Cross-Platform Considerations

  • Web: Store tokens in httpOnly cookies (not localStorage)
  • Mobile: Use platform secure storage (Keychain, EncryptedSharedPreferences)
  • Desktop: Use OS credential manager

Multi-Tenant Security

For SaaS applications, ensure complete data isolation between tenants:

-- RLS policy for multi-tenant isolation
CREATE POLICY "Tenant isolation"
  ON documents FOR ALL
  USING (
    organization_id IN (
      SELECT org_id FROM organization_members
      WHERE user_id = auth.uid()
    )
  )
  WITH CHECK (
    organization_id IN (
      SELECT org_id FROM organization_members
      WHERE user_id = auth.uid()
    )
  );

Test tenant isolation thoroughly. A single missing policy can leak data across organizations.

Security Testing Strategy

  1. Policy Testing: Write automated tests for every RLS policy and security rule
  2. Penetration Testing: Test with the anon key, authenticated as different users, cross-tenant
  3. Automated Scanning: Use AuditYour.app to continuously monitor your BaaS configuration
  4. Dependency Auditing: Keep client libraries updated and monitor for vulnerabilities

Incident Response

Prepare for security incidents before they happen:

  1. Know how to revoke API keys and rotate secrets
  2. Have monitoring in place to detect anomalous access patterns
  3. Maintain an audit log of all data access
  4. Document the process for disabling public API access in an emergency
  5. Practice your response procedure

Scan your app for this vulnerability

AuditYourApp automatically detects security misconfigurations in Supabase and Firebase projects. Get actionable remediation in minutes.

Run Free Scan