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 |
SSO Deep Links
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,
});
}