04 · Request & auth flow
How a browser or device becomes a trusted actor inside a specific tenant.
Typical staff API request
sequenceDiagram
participant B as Browser SPA
participant N as Nginx
participant E as Express
participant S as sessionAuth
participant T as tenantResolver
participant F as featureGate / roles
participant R as Route + Service
participant D as Tenant MySQL
B->>N: HTTPS + cookie pawspos.sid
N->>E: proxy /api/*
E->>S: requireSessionAuth
S-->>E: req.user
E->>T: resolve tenant / org
T-->>E: req.tenant slug orgId
E->>F: plan module + role checks
E->>R: handler
R->>D: getTenantConnection(slug, type)
D-->>R: rows
R-->>B: JSON
Identity layers (do not collapse these)
| Layer | What it proves | Where |
|---|---|---|
| Platform session | Logged-in user of the SaaS | Cookie session · sessionAuth.js |
| Tenant context | Which business DB | tenantResolver.js · headers/session |
| POS PIN staff | Which cashier on the register | Browser localStorage after /register/authenticate |
| Device credential | Paired kiosk/mobile hardware | x-device-id + x-device-secret · deviceAuth.js |
| Master admin role | Platform operator | requireRoles('master_admin') |
| HR admin role | Can see payroll/PII | requireHRAdminRole |
Hardened (audit)
Session secret set, cookie Secure in production, device secrets issued, HR sensitive routes role-gated.
Legacy unpaired devices still work until regenerated (rollout task).
Public / special mounts
flowchart LR
subgraph PUBLIC
W[Webhooks raw body]
PB[public barcode-lookup rate limit]
SF[storefront public config]
SIG[signage playlist GET]
EMP[employee portal login]
end
subgraph SESSION
POS["/api/pos/*"]
ADM[admin routes]
end
subgraph DEVICE
K["/api/kiosk · /api/mobile
optionalSession + deviceAuth"]
end
PUBLIC --> API[Express]
SESSION --> API
DEVICE --> API