Skip to content

Authentication — Foot Factory

Foot Factory delegates all authentication to Supabase Auth. There are no local passwords, no custom JWTs, and no refresh tokens managed by Foot Factory itself.

How It Works

sequenceDiagram
    participant U as User
    participant SB as Supabase Auth
    participant PA as Portal API
    participant FF as Foot Factory API

    U->>SB: Login (email + password)
    SB-->>U: JWT with app_metadata
    note over U,SB: app_metadata contains:\nactiveTenantId, activeRole,\nactiveAppAccess, tenants[]

    U->>FF: API request (Bearer JWT)
    FF->>SB: supabase.auth.getUser(token)
    SB-->>FF: Validated user + app_metadata
    FF->>FF: Extract activeTenantId, activeRole
    FF->>FF: Scope all queries to activeTenantId
    FF-->>U: Response (tenant-scoped data)

JWT Structure

Every request to Foot Factory API must include a valid Supabase JWT:

Authorization: Bearer <supabase_jwt>

The JWT app_metadata contains:

{
  "activeTenantId": "uuid-of-active-tenant",
  "activeRole": "tenant-admin",
  "activeAppAccess": ["foot-factory"],
  "tenants": [
    {
      "tenantId": "uuid",
      "tenantName": "Acme Corp",
      "role": "tenant-admin",
      "apps": ["foot-factory"],
      "appSubdomains": {
        "foot-factory": "acme-corp.foot-factory.dotevolve.net"
      }
    }
  ]
}

protect Middleware

The protect middleware in dot-foot-factory-api validates every incoming request:

// Simplified protect middleware
const {
  data: { user },
  error,
} = await supabase.auth.getUser(token);
if (error || !user) throw new AuthenticationError("Invalid or expired token");

// Check tenant status
const { data: tenant } = await supabaseAdmin
  .from("tenants")
  .select("status")
  .eq("id", meta.activeTenantId)
  .single();

if (tenant?.status === "suspended")
  throw new AppError("Tenant is suspended", 403);
if (tenant?.status === "pending_payment")
  throw new AppError("Payment required", 402);

req.user = {
  id: user.id,
  email: user.email,
  activeTenantId: meta.activeTenantId,
  activeRole: meta.activeRole,
  app_metadata: meta,
};

Status Codes

Tenant Status HTTP Response
active Request proceeds normally
suspended 403 Forbidden
pending_payment 402 Payment Required
Missing JWT 401 Unauthorized
Expired JWT 401 Unauthorized

The Admin Portal can generate SSO deep links into foot-factory-admin:

https://foot-factory-admin.dotevolve.net/auth/sso?token=<jwt>&tenantId=<id>

The /auth/sso route validates the JWT via Supabase, sets the session, and redirects to the dashboard with the correct tenant context.

Lazy Profile Creation

If a user's Supabase account exists but no MongoDB User document has been created yet (e.g. webhook delivery failed), the protect middleware creates the profile document on the first authenticated request:

let profile = await User.findOne({ supabaseId: user.id });
if (!profile) {
  profile = await User.create({
    supabaseId: user.id,
    email: user.email,
    name: user.email,
  });
}