Authentication
Four cookie types, per-route role enforcement, and how to make authenticated calls.
Overview
Restora 360 uses HTTP-only, HS256-signed JWT session cookies. Cookies are set on the platform host and (for tenant routes) the tenant subdomain. There are four distinct cookies so that, e.g. a super-admin signed into /admin and a tenant owner signed into a customer storefront in the same browser never collide.
The four cookies
| Cookie | Role | Used by | |---|---|---| | platform_session | tenant-owner / web-designer / sales-agent | Tenant dashboards, designer + agent portals | | admin_session | superadmin | Super-admin panel only (separate cookie to avoid collisions) | | customer_session | per-tenant customer | Tenant storefronts (registered customer accounts) | | ref_code | non-PII | First-touch sales-agent referral attribution (90-day TTL) |
Cookies are HttpOnly, SameSite=Lax, Secure in production, and JWT-signed with the platform's SESSION_SECRET env var.
Logging in
A successful POST to /api/auth/login sets platform_session (or admin_session if the user has role=superadmin). The response body returns { ok: true, role, tenantId? } — never the JWT itself.
Example — logged-in fetch
curl -X POST \
-H "Content-Type: application/json" \
-d '{"email":"owner@luigi.com","password":"password123"}' \
-c cookies.txt \
https://api.restora360.com/api/auth/login
# Subsequent calls reuse the cookie
curl -b cookies.txt https://api.restora360.com/api/tenant/luigi-pizza/ordersRole enforcement on the server
Every protected route calls one of the auth helpers (src/lib/auth/api-auth.ts):
requireTenantAccess(tenantId)— caller must own / co-manage the tenant, OR be a super-adminrequireSuperAdmin()—admin_sessiononlyrequireWebDesigner()—platform_sessionwithrole=web-designerrequireSalesAgent()—platform_sessionwithrole=sales-agentrequireGroupAccess(orgId)— HQ-tenant owner OR group-manager withorganizationIdmatchrequireCustomerAuth(tenantId)—customer_sessionscoped to the same tenant
Each returns either { session, ...context } or { error: Response }. Routes that don't guard are public.
Logging out
POST /api/auth/logout clears the relevant cookie (platform_session by default, admin_session when called from /admin/logout). Idempotent — calling it without a session is a no-op 200.
Frequently asked
- Not yet. API keys are coming in a follow-up to Phase 3. Until then, persist a long-lived session by saving the `platform_session` cookie server-side and refreshing it before expiry (24-hour default TTL).
- Change `SESSION_SECRET` and redeploy. All existing sessions invalidate — users must log in again.