Skip to main content

ADR-0001: Authentication and Authorization Architecture

Status

Accepted - 2025-10-24


Context

TVL Platform requires secure authentication and authorization for a multi-tenant SaaS application with the following requirements:

Business Requirements

  • Property managers, owners, and staff need differentiated access
  • Multiple users per organization with role-based permissions
  • Property-level access delegation (manager can access only assigned properties)
  • Audit trail of all access and actions
  • Support for API consumers (web UI, future mobile apps, integrations)

Technical Requirements

  • Secure authentication without implementing custom password management
  • Token-based auth suitable for stateless APIs
  • Row-Level Security (RLS) for tenant isolation in Postgres
  • Performance: auth checks < 50ms per request
  • Compliance: GDPR, SOC 2 Type II readiness

Constraints

  • MVP timeline: 3 months
  • Small team (2-3 engineers)
  • Preference for managed services over custom implementation
  • Must integrate with Supabase (Postgres provider)

Decision

We will implement a hybrid authentication and authorization architecture:

Authentication (AuthN)

Google OIDC via Supabase Auth for user authentication

Rationale:

  • Supabase Auth provides managed OIDC integration (no custom password logic)
  • Google OIDC is familiar to business users (high adoption)
  • JWT tokens suitable for stateless API architecture
  • Built-in token refresh, session management
  • Reduces security surface area (Google handles credentials)

Implementation:

// Authentication flow
1. User clicks "Sign in with Google"
2. Redirect to Google OAuth consent
3. Google returns authorization code
4. Exchange code for ID token (Supabase Auth)
5. Verify ID token and create/update user record
6. Issue JWT with claims: { userId, organizationId, role }
7. Client stores JWT in localStorage (web) or secure storage (mobile)

Authorization (AuthZ)

Role-Based Access Control (RBAC) with Property-Level Delegation

Roles:

  1. Owner - Full access to organization and owned properties
  2. Manager - Full access to assigned properties only
  3. Staff - Limited write access to assigned properties
  4. Finance - Read-only financial data across organization
  5. Admin - TVL internal super-admin (cross-tenant access)

Permission Model:

  • Permissions stored in database (permissions table)
  • Role-permission mappings in role_permissions table
  • User-role assignments in org_members table with optional property scope
  • Property-level assignments in property_assignments table

Authorization Checks:

// Request flow
1. Extract JWT from Authorization header
2. Validate JWT signature and expiration
3. Extract userId, organizationId from claims
4. Check if user belongs to organization
5. Check user's role for organization
6. If property-specific operation, check property assignment
7. Enforce permission requirements for endpoint

Tenant Isolation

Row-Level Security (RLS) in Postgres/Supabase

Rationale:

  • Defense-in-depth: even if application logic fails, RLS prevents cross-tenant access
  • Supabase makes RLS easy to implement
  • No performance penalty if properly indexed

RLS Policies:

-- Example: properties table
CREATE POLICY "Users can only access properties in their org"
ON properties
FOR ALL
USING (organization_id = current_setting('app.current_org_id')::uuid);

-- Set org context at start of transaction
SET LOCAL app.current_org_id = '<orgId from JWT>';

Alternatives Considered

Alternative 1: Custom Username/Password Auth

Rejected

Pros:

  • Full control over auth flow
  • No dependency on external provider

Cons:

  • High security risk (password storage, hashing, salting, breach response)
  • Must implement password reset, 2FA, account recovery
  • Compliance burden (password policies, breach notification)
  • Significant development time (2-4 weeks)

Decision: Leverage Google's security infrastructure instead


Alternative 2: Auth0 or AWS Cognito

Rejected (for MVP, reconsidered for future)

Pros:

  • Enterprise-grade features (SSO, MFA, advanced RBAC)
  • Comprehensive identity management
  • Better for complex auth scenarios

Cons:

  • Additional cost ($240-$1200/year for MVP scale)
  • Complexity for simple use case
  • Another external dependency
  • Supabase Auth is already included

Decision: Use Supabase Auth for MVP; migrate to Auth0 if enterprise SSO required


Alternative 3: Attribute-Based Access Control (ABAC)

Rejected (for MVP, possible future enhancement)

Pros:

  • Fine-grained permissions (e.g., "can edit properties with < 10 units")
  • More flexible than RBAC
  • Better for complex authorization scenarios

Cons:

  • Significantly more complex to implement and debug
  • Performance impact (rule evaluation on every request)
  • Harder for non-technical users to understand
  • Overkill for MVP requirements

Decision: Start with RBAC; add ABAC-style rules if customer demand warrants


Alternative 4: API Keys for Authentication

Rejected

Pros:

  • Simpler than OAuth for programmatic access
  • No token refresh logic

Cons:

  • Not suitable for human users (no expiration, hard to revoke)
  • Poor UX (users must manage keys)
  • Security risk (long-lived credentials)

Decision: JWT for human users; API keys may be added for machine-to-machine in future


Consequences

Positive

  1. Security

    • No password management burden
    • Google handles credential security
    • Short-lived JWT tokens (24h expiration)
    • RLS provides defense-in-depth
  2. Developer Experience

    • Supabase Auth SDK simplifies implementation
    • JWT standard widely supported
    • Clear RBAC model easy to reason about
  3. User Experience

    • Familiar "Sign in with Google" flow
    • No password to remember
    • Fast authentication (< 2s)
  4. Compliance

    • GDPR: User can delete Google account
    • SOC 2: Leverages Google's certifications
    • Audit trail via RLS and application logs
  5. Cost

    • Supabase Auth included in plan (no extra cost)
    • No Auth0/Cognito fees

Negative

  1. Vendor Lock-in

    • Dependent on Google OIDC (if Google changes policy, major impact)
    • Dependent on Supabase Auth (migration effort if switching providers)
    • Mitigation: OAuth/OIDC is standard; can migrate to another provider with effort
  2. Limited Social Login

    • Only Google OIDC for MVP (no Facebook, Apple, Microsoft)
    • Mitigation: Add more providers if customer demand; Supabase supports multiple
  3. RBAC Rigidity

    • Fixed roles may not fit all customer workflows
    • Mitigation: Document customization path; consider ABAC post-MVP
  4. JWT Statelessness Trade-off

    • Cannot revoke JWT before expiration (24h window)
    • Mitigation: Keep expiration short; implement token blacklist if needed
  5. Property-Level Permissions Complexity

    • Junction table for property assignments adds query complexity
    • Performance impact if not properly indexed
    • Mitigation: Add composite indexes on (user_id, organization_id, property_id)

Implementation Plan

Phase 1: Authentication (Week 1-2)

  1. Integrate Supabase Auth with Google OIDC
  2. Implement JWT validation middleware
  3. Create user registration/login endpoints
  4. Add session management (token refresh)

Phase 2: Basic Authorization (Week 3-4)

  1. Create roles, permissions, role_permissions tables
  2. Seed predefined roles and permissions
  3. Implement RBAC middleware
  4. Add user-role assignment endpoints

Phase 3: Property-Level Delegation (Week 5-6)

  1. Create property_assignments table
  2. Implement property-level auth checks
  3. Add property assignment management UI
  4. Test delegation workflows

Phase 4: RLS (Week 7-8)

  1. Enable RLS on all tenant-scoped tables
  2. Create RLS policies
  3. Update application to set org context
  4. Test cross-tenant isolation

Phase 5: Audit & Security Hardening (Week 9-10)

  1. Add audit logging for all auth events
  2. Implement rate limiting on auth endpoints
  3. Security audit and penetration testing
  4. Documentation and runbooks

Validation Checklist

  • User can sign in with Google
  • JWT tokens issued with correct claims
  • Token expiration enforced (24h)
  • Role-based permissions block unauthorized actions
  • Property-level delegation works correctly
  • RLS prevents cross-tenant data access
  • Audit logs capture auth events
  • Rate limiting prevents brute-force attacks
  • Performance: auth checks < 50ms (p95)
  • Security: No secrets in client-side code
  • Compliance: GDPR data export includes auth logs

References


Appendix: Permission Matrix

RoleCreate PropertyEdit PropertyDelete PropertyView BookingsManage PaymentsManage Users
Owner
Manager✅ (assigned)✅ (assigned)✅ (assigned)
Staff✅ (limited)✅ (assigned)
Finance✅ (read-only)✅ (read-only)
Admin✅ (all orgs)✅ (all orgs)✅ (all orgs)✅ (all orgs)✅ (all orgs)✅ (all orgs)

Sources

  • meta/research-log.md
  • docs/02-domains/identity-access/spec.md
  • docs/00-overview/platform-overview.md