HDB Service uses Supabase Auth with server-side rendered (SSR) cookies for session management. There are no API keys or Bearer tokens for regular API access — when a user logs in, Supabase sets an HTTP-only session cookie in the browser, and every subsequent API call is authenticated automatically through that cookie. The session is opaque to JavaScript running in the page, making it resistant to XSS-based token theft.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/GianlucaBessone/HDB-Service/llms.txt
Use this file to discover all available pages before exploring further.
How Authentication Works
Every protected API route follows the same server-side validation pipeline, implemented acrossutils/supabase/server.ts, lib/auth.ts, and lib/rbac.ts:
Step 1 — Login via Supabase Auth
The user authenticates with their email and password through Supabase’s Auth system. On success, Supabase sets an HTTP-only session cookie in the browser. This cookie is the sole credential for all subsequent API calls.
Step 2 — Middleware session refresh
The Next.js middleware (middleware.ts) intercepts every incoming request and calls updateSession() from utils/supabase/middleware.ts. This function creates a server-side Supabase client from the incoming cookies and calls supabase.auth.getUser() to silently refresh the session token if it is near expiry, writing updated cookie values back to the response. This keeps long-lived sessions valid without requiring a manual re-login.
requirePermission()
Each API route handler calls requirePermission(permission) from lib/auth.ts, passing the specific permission string required to execute that action. The function:
- Creates a server-side Supabase client via
createClient()(reads the session cookie vianext/headers). - Calls
supabase.auth.getUser()to retrieve the authenticated Supabase identity. - Looks up the matching
Userrecord in PostgreSQL via Prisma, using the user’s email as the join key. - Verifies the user’s
activeflag — inactive users are rejected as if unauthenticated. - Calls
hasPermission(role, permission)fromlib/rbac.tsto check the role’s permission set. - Returns the fully-hydrated
SessionUserobject on success, or aNextResponsewith401/403on failure.
Session User Object
When authentication and authorization succeed,requirePermission() (and getCurrentUser()) return a SessionUser object that every route handler works with:
clientId and plantIds drive automatic data scoping. CLIENT_RESPONSIBLE users only see records belonging to their clientId. CLIENT_REQUESTER users only see records tied to one of their plantIds. This is enforced server-side via getDataFilter() in lib/auth.ts.Role-Based Access Control (RBAC)
Every permission in the system is defined as a string literal inlib/rbac.ts and mapped to one or more roles in the ROLE_PERMISSIONS matrix. Calling requirePermission('permission:action') will reject the request with 403 Forbidden if the authenticated user’s role is not in the allowed set.
Available roles and their access level:
| Role | Description |
|---|---|
ADMIN | Full access to all resources, user management, SLA configuration, and audit logs |
SUPERVISOR | Full operational access; cannot manage sla_config or audit |
TECHNICIAN | Read/write access to tickets, maintenance, and stock; read-only for dispensers |
CLIENT_RESPONSIBLE | Scoped to their client; can create tickets, view reports, release dispenser blocks |
CLIENT_REQUESTER | Scoped to their plant(s); can create and read tickets and view their dispensers |
GET /api/auth/me
Returns theSessionUser object for the currently authenticated session. This endpoint is used by the frontend to hydrate the user context on page load.
Request
200 OK)
401 Unauthorized)
POST /api/auth/change-password
Changes the password for the currently authenticated user. This endpoint updates the password in both Supabase Auth (via the Admin API) and in the PrismaUser record (as a bcrypt hash), then clears the mustChangePassword flag.
Request
The new password. Must be at least 6 characters long.
200 OK)
400 Bad Request)
401 Unauthorized)
Force Password Change
When an administrator creates a new user with a temporary password, themustChangePassword flag is set to true on the Prisma User record. The frontend reads this flag from GET /api/auth/me and renders a ForcePasswordChangeModal that blocks access to all application pages until the user completes a password change via POST /api/auth/change-password. Once the password is changed successfully, the handler sets mustChangePassword: false in the database.
Public Routes
The following routes do not require an authenticated session and can be called without a session cookie:| Route | Method | Description |
|---|---|---|
GET /api/health | GET | Health check — verifies API and database connectivity |
POST /api/public/verify | POST | Cryptographically verify a maintenance approval signature hash |
GET /api/public/approvals/[id] | GET | View a public maintenance approval record by ID |
PUT /api/public/approvals/[id] | PUT | Submit a customer digital signature for a maintenance approval |
/api/cron route is not publicly accessible — it requires an Authorization: Bearer <CRON_SECRET> header matching the CRON_SECRET environment variable. This is used by Vercel Cron Jobs for automated daily tasks (SLA checks, maintenance schedule generation, monthly closures).
Making Authenticated Requests from External Tools
HDB Service is designed for browser-based use. For external HTTP clients (curl, Postman, custom integration scripts), authentication requires one of the following approaches: Option 1 — Export a browser session cookie (for testing)- Log in to the HDB Service web app in your browser.
- Open DevTools → Application → Cookies. Copy the Supabase session cookie (typically named
sb-*-auth-token). - Pass the cookie value in your request:
access_token (JWT) and a refresh_token. You can then use the Supabase JS/Python client library to set the session and call HDB Service API routes, or manually construct the cookie expected by @supabase/ssr.