Skip to content

Authentication & SSO

All DotEvolve products share a single identity provider: Supabase Auth. Users log in once and access all their assigned apps without re-authenticating.

JWT Structure

Every authenticated request carries a Supabase JWT. The app_metadata claims are set by dot-portal-api and injected into every token via a custom access token hook.

{
  "sub": "uuid",
  "email": "user@example.com",
  "app_metadata": {
    "activeTenantId": "uuid-A",
    "activeRole": "tenant-admin",
    "activeAppAccess": ["foot-factory", "dot-cos"],
    "tenants": [
      {
        "tenantId": "uuid-A",
        "tenantName": "Acme Corp",
        "role": "tenant-admin",
        "apps": ["foot-factory", "dot-cos"],
        "appSubdomains": {
          "foot-factory": "acme-corp.foot-factory.dotevolve.net",
          "dot-cos": "acme-corp.cos.dotevolve.net"
        }
      }
    ]
  }
}

Login Flow

sequenceDiagram
    participant U as User
    participant SB as Supabase Auth
    participant PA as Portal API

    U->>SB: Login (email + password)
    SB->>SB: Run custom_access_token_hook
    SB->>SB: Merge raw_app_meta_data into JWT claims
    SB-->>U: JWT with app_metadata
    U->>PA: API request (Bearer JWT)
    PA->>SB: Validate JWT (public key)
    SB-->>PA: Validated user + app_metadata

Active Tenant Switching

Admins who manage multiple tenants use the Tenant Picker to switch context:

  1. User selects a tenant card in the Admin Portal
  2. Admin Portal calls POST /api/v1/users/me/active-tenant with { tenantId }
  3. dot-portal-api updates app_metadata.activeTenantId, activeRole, activeAppAccess
  4. Admin Portal calls supabase.auth.refreshSession() to get a new JWT
  5. Admin Portal navigates to /tenants/:tenantId

dot-admin can generate SSO deep links into app dashboards (dot-foot-factory-admin, dot-cos-admin-dashboard). The link format is:

https://{app-subdomain}/auth/sso?token=<jwt>&tenantId=<id>

The receiving app validates the JWT via Supabase, sets the session, and redirects to its home page with the correct tenant context loaded.

Downstream JWT Validation

Both dot-foot-factory-api and dot-cos-workflow-service validate JWTs using the Supabase public key. They extract activeTenantId and activeRole from app_metadata claims — no HTTP call to any auth service is needed at request time.

// dot-foot-factory-api protect middleware
const {
  data: { user },
  error,
} = await supabase.auth.getUser(token);
const meta = user.app_metadata ?? {};
req.user = {
  id: user.id,
  email: user.email,
  activeTenantId: meta.activeTenantId,
  activeRole: meta.activeRole,
  app_metadata: meta,
};
// dot-cos-api-gateway resolveTenant
const tenantId = req.user?.app_metadata?.activeTenantId;
req.tenantId = tenantId;
req.headers["x-tenant-id"] = tenantId;