Skip to content

Authentication & Authorization

PIP AI uses Supabase Auth for authentication and Row Level Security (RLS) for authorization.

Authentication Flow

mermaid
sequenceDiagram
    participant U as User
    participant App as Nuxt App
    participant Auth as Supabase Auth
    participant DB as PostgreSQL

    U->>App: Navigate to protected route
    App->>App: auth middleware checks session
    alt No session
        App->>U: Redirect to /auth/login
        U->>Auth: Sign in (email/password)
        Auth->>Auth: Validate credentials
        Auth->>U: Return JWT + refresh token
        U->>App: Redirect to callback
        App->>App: Store session
    end
    App->>DB: Query with JWT (RLS enforced)
    DB->>App: Filtered results

User Roles

RoleCapabilities
AdminFull access to all data, manage users, upload specs, access all projects
UserCreate/manage own projects, access specs for brands in their projects only

First User Setup

The first user to register is automatically promoted to admin via the pip_ai_handle_new_user() trigger.

JWT Custom Claims

A JWT hook (pip_ai_custom_access_token_hook) adds custom claims to every access token:

json
{
  "role": "admin",
  "is_active": true
}

Auth Middleware

app/middleware/auth.ts

Checks for a valid Supabase session. Redirects unauthenticated users to /auth/login.

When NUXT_PUBLIC_DEV_AUTH_BYPASS=true, this middleware is completely skipped.

app/middleware/admin.ts

Restricts routes to admin users by checking the user's role via the pip_ai_check_is_admin() RPC function.

Row Level Security (RLS)

All tables have RLS enabled. Policies use helper functions to avoid infinite recursion:

Key Helper Functions

FunctionPurpose
pip_ai_check_is_admin()SECURITY DEFINER function checking admin role (avoids RLS recursion)
pip_ai_is_project_member(project_id)Check if current user is a member of a project
pip_ai_can_edit_project(project_id)Check if current user can edit a project (owner/editor/admin)
pip_ai_get_project_role(project_id)Get user's role in a project

Policy Summary

DataWho Can ReadWho Can Write
ProjectsMembers + AdminOwner/Editor + Admin
PIP ItemsProject members + AdminProject editors + Admin
Spec SectionsAdmin + users with matching brand projectsAdmin only
MatchesVia PIP item membershipVia PIP item edit access
Floor PlansProject members + AdminProject editors + Admin
User ProfilesOwn profile + AdminOwn profile + Admin

Brand Isolation

Users can only read pip_ai_spec_sections where the brand_name matches a brand they have projects for:

sql
brand_name IN (
  SELECT DISTINCT brand_name
  FROM pip_ai_projects
  WHERE created_by = auth.uid()
)

Dev Auth Bypass

For local development, set:

ini
NUXT_PUBLIC_DEV_AUTH_BYPASS=true

Effects:

  • Auth middleware skipped
  • Supabase redirect disabled in nuxt.config.ts
  • Mock user session created
  • Client-side RLS effectively bypassed

DANGER

Never enable dev auth bypass in production.

Server-Side Auth

Server routes (server/api/) use the service role key to bypass RLS:

typescript
const client = await serverSupabaseServiceRole(event)

Webhook callbacks authenticate via a shared secret header:

typescript
const secret = event.headers.get('x-webhook-secret')

Project Membership

Projects support collaborative access with three roles:

RoleViewEditDeleteManage Members
OwnerYesYesYesYes
EditorYesYesNoNo
ViewerYesNoNoNo

When a project is created, the creator is automatically added as owner via a database trigger.

Built with VitePress