16 KiB
Route Access Inventory
This document publishes the checked Hono API route access classification from apps/api/src/route-access-inventory.ts. It is a static security review aid only: it records route boundaries, access classes, rationale, and redacted data-sensitivity notes without changing route handlers, OpenAPI metadata, authorization middleware, or runtime behavior.
Historical-plan note: route keys and access classes in this document are current only when the focused verification below passes. Do not copy route paths from older improvement-plan files into this inventory without confirming the typed source of truth.
Scope and Source of Truth
- Source of truth:
apps/api/src/route-access-inventory.ts. - Scanner reference:
tools/api-inventory/scan-api-routes.tsdiscoversapp.get/post/patch/deleteroute registrations fromapps/api/src/app.tsfor coverage checks. - Verification:
apps/api/src/route-access-inventory.test.tschecks scanner-discovered route coverage and OpenAPI security expectations;apps/api/src/route-access-inventory-doc.test.tschecks this document for drift. - Route keys are written as
METHOD pathand must match the typed inventory exactly once. - This inventory covers all current Hono API routes, including health, documentation, authentication, analytics, accounts, usage, notifications, workspaces, entity, relationship, export, webhook, maintenance, and AI upload surfaces.
- Adjacent coverage:
docs/security/csrf-inventory.mddocuments CSRF posture and mutating API route classes. This document references that coverage but does not duplicate its mutating-route-only table.
Redaction Rules
- Do not include tokens, plaintext credentials, fixture tenant identifiers, customer data, environment variable values, or concrete database identifiers.
- Keep sensitive-data notes categorical and redacted, for example “returns aggregate counts” or “consumes uploaded file content.”
- Do not paste authorization headers, JWTs, API keys, passwords, emails, tenant fixtures, or customer examples into this document.
- Route parameters such as
:entity,:rowId, and:idare schema placeholders, not real identifiers.
Access Class Legend
| Class | Boundary |
|---|---|
public-health |
Unauthenticated infrastructure health or readiness endpoint exposing only service/dependency status metadata. |
public-docs |
Unauthenticated API documentation or schema discovery surface exposing schema metadata only. |
service-token |
Service/API-token style boundary, including stored API key or service credential checks where implemented. |
service-or-tenant-api-key |
Service credential or tenant-bound stored API-key boundary with route-specific tenant and permission checks. |
optional-api-key-validation |
Public validation helper that optionally accepts a presented stored API key or service token and returns redacted validation status. |
tenant-api-key |
Tenant-bound stored API-key boundary where the credential scopes the tenant and available usage metadata. |
jwt-auth |
Bearer JWT authenticated user boundary. |
auth-credential-exchange |
Public credential exchange that consumes submitted credentials and issues authenticated API state after validation. |
public-analytics-token |
Public analytics ingress or aggregate read surface scoped by analytics token/payload semantics rather than browser session state. |
webhook-signature |
Signed webhook ingress boundary that verifies provider signing headers before processing an addressed webhook retry. |
canonical-redirect |
Runtime-only compatibility shim that redirects removed API-prefix requests to the canonical API path without reading request data. |
Full Route Access Table
| Route | Access class | Sensitive data note | Rationale |
|---|---|---|---|
GET /healthz |
public-health |
No sensitive data. | Unauthenticated liveness probe returns only service status and request correlation metadata. |
GET /readyz |
public-health |
Dependency health state is exposed without implementation details. | Unauthenticated readiness probe returns redacted dependency status for infrastructure checks. |
GET /v1/health |
public-health |
No sensitive data. | Versioned liveness probe returns only service status and request correlation metadata. |
GET /v1/openapi.json |
public-docs |
No sensitive data. | OpenAPI discovery is intentionally public for client integration and contains schema metadata only. |
GET /v1/docs |
public-docs |
No sensitive data. | Documentation shell is intentionally public and renders the OpenAPI document without runtime data. |
GET /v1/session/current-user |
service-token |
Returns authenticated principal type metadata only. | Current service principal endpoint requires a bearer service token before returning authentication state. |
POST /v1/auth/login |
auth-credential-exchange |
Consumes credentials and returns a JWT plus basic user identity. | Login exchanges submitted email and password credentials for a short-lived JWT after password verification. |
POST /v1/auth/refresh-token |
jwt-auth |
Returns a JWT plus basic user identity. | Refresh requires an existing bearer JWT before issuing a replacement token for the same user. |
POST /v1/auth/logout |
jwt-auth |
Consumes JWT credential material but returns only a success envelope and expired cookie attributes. | Logout requires an existing bearer JWT before revoking the active API session and clearing the API cookie. |
POST /v1/api-keys/validate |
optional-api-key-validation |
Returns redacted stored API-key metadata but never plaintext key material. | API-key validation optionally accepts a presented stored API key or service token and reports redacted validation status without requiring a prior credential. |
POST /v1/ai/upload |
service-token |
Consumes uploaded file content and may return a public storage URL. | AI upload writes request content through configured service storage credentials and depends on server-side upload configuration. |
POST /v1/support/inbound-email |
webhook-signature |
Consumes signed email metadata and message body while omitting provider payloads and signing material from responses. | Inbound support email verifies Mailjet webhook signing headers before resolving tenant inbound addresses and creating tickets. |
POST /v1/analytics/events |
public-analytics-token |
Consumes analytics identifiers, URLs, routes, and event labels. | Analytics event ingestion is public-facing and scoped by analytics payload identifiers rather than browser session state. |
POST /v1/analytics/page-views |
public-analytics-token |
Consumes analytics identifiers, URLs, and route names. | Analytics page-view ingestion is public-facing and scoped by analytics payload identifiers plus ignore-page settings. |
GET /v1/analytics/public |
public-analytics-token |
Returns aggregate analytics counts and top-level chart data. | Public analytics overview requires the analytics token header before returning aggregate metrics. |
GET /v1/analytics/admin |
service-token |
Returns aggregate analytics metrics that may be scoped to a portal identifier. | Admin analytics overview requires service credentials before returning tenant or portal scoped metrics. |
GET /v1/notifications/stream |
service-token |
Returns bounded, sanitized notification delivery snapshots and cursors without provider payloads, metadata, or raw delivery secrets. | Notification stream requires service credentials before returning tenant and user scoped in-app delivery diagnostics over SSE. |
GET /v1/accounts |
service-token |
Returns tenant identifiers, names, slugs, icons, and subscription summary fields without plaintext secrets. | Account listing requires service credentials before returning tenant account metadata and subscription summaries. |
GET /v1/accounts/:id |
service-token |
Returns tenant identifiers, names, slugs, icons, and subscription summary fields without plaintext secrets. | Account lookup requires service credentials before returning one tenant account metadata and subscription summary. |
GET /v1/usage |
tenant-api-key |
Returns plan and remaining API usage metadata for the credential-scoped tenant. | Usage lookups enter through the canonical API host and validate tenant API-key credentials in the API runtime. |
POST /v1/billing/stripe/webhooks |
webhook-signature |
Consumes signed billing lifecycle webhook payloads without returning signing material or plaintext credentials. | Stripe billing webhook ingress enters through the canonical API host and verifies the raw signed payload in the API runtime. |
POST /v1/email-sequences/mailjet/webhooks |
webhook-signature |
Consumes signed delivery event metadata while responses omit provider payloads, recipient data, and signing material. | Email-sequence provider webhooks verify Mailjet signing headers before correlating bounce events to provider message ids. |
GET /v1/workspaces/:tenantId/auth/providers |
service-token |
Returns redacted OIDC/SAML provider metadata only; client secrets, SAML certificate bodies, private keys, token hashes, invite tokens, and raw metadata documents are omitted. | Workspace auth-provider discovery requires a service token before returning tenant-scoped SSO metadata. |
POST /v1/workspaces/:tenantId/context/revalidate |
service-token |
Consumes tenant and user identifiers and returns a redacted validity envelope without provider secrets, invite tokens, token hashes, or SSO secret material. | Workspace context revalidation requires a service token before confirming tenant/user membership for a context switch. |
GET /v1/workspaces/:tenantId/invites |
service-token |
Returns invite recipient details, lifecycle timestamps, audit user ids, and tokenPrefix only; plaintext tokens and token hashes are omitted. | Workspace invite listing requires a service token before returning tenant-scoped invite lifecycle state. |
POST /v1/workspaces/:tenantId/invites |
service-token |
Consumes invite recipient details and returns the one-time plaintext invite token only in the create response. | Workspace invite creation requires a service token before issuing a tenant-scoped invite token. |
POST /v1/workspaces/:tenantId/invites/:inviteId/accept |
service-token |
Consumes plaintext invite token and returns redacted invite lifecycle metadata without echoing the token. | Workspace invite acceptance requires a service token and a one-time invite token before finalizing tenant membership invitation state. |
POST /v1/workspaces/:tenantId/invites/:inviteId/revoke |
service-token |
Consumes revoke audit metadata and returns redacted invite lifecycle metadata without token material. | Workspace invite revocation requires a service token before finalizing the tenant-scoped invite as revoked. |
POST /v1/events/webhooks/attempts/:id |
webhook-signature |
Consumes signed webhook delivery metadata and an attempt id while omitting provider payloads and signing material from responses. | Webhook retry verifies Mailjet webhook signing headers before looking up or queueing a known delivery attempt. |
POST /v1/maintenance/export-retention/enqueue |
service-token |
Consumes an optional bounded batch size and returns only queue task metadata plus request correlation. | Export artifact retention cleanup is an operator maintenance action and requires service credentials before enqueueing work. |
GET /v1/entities/:entity/rows |
service-or-tenant-api-key |
Returns tenant-scoped legacy entity row data. | Entity row listing requires a service token or scoped stored API key with read permission for the resolved entity. |
POST /v1/entities/:entity/rows |
service-or-tenant-api-key |
Consumes and stores tenant-scoped legacy entity row data. | Entity row creation requires a service token or scoped stored API key with create permission for the resolved entity. |
GET /v1/entities/:entity/rows/:rowId |
service-or-tenant-api-key |
Returns tenant-scoped legacy entity row data. | Entity row lookup requires a service token or scoped stored API key with read permission for the resolved entity. |
PATCH /v1/entities/:entity/rows/:rowId |
service-or-tenant-api-key |
Consumes and returns tenant-scoped legacy entity row data. | Entity row update requires a service token or scoped stored API key with update permission for the resolved entity. |
DELETE /v1/entities/:entity/rows/:rowId |
service-or-tenant-api-key |
Deletes tenant-scoped legacy entity row data and returns the deleted row id. | Entity row deletion requires a service token or scoped stored API key with delete permission for the resolved entity. |
POST /v1/relationships |
service-or-tenant-api-key |
Consumes row identifiers and returns relationship metadata. | Relationship creation requires a service token or scoped stored API key with create permission for both related entities. |
GET /v1/relationships/:id |
service-or-tenant-api-key |
Returns relationship metadata with parent and child row envelopes. | Relationship lookup requires a service token or scoped stored API key with read permission for both related entities. |
DELETE /v1/relationships/:id |
service-or-tenant-api-key |
Deletes and returns relationship metadata with parent and child row envelopes. | Relationship deletion requires a service token or scoped stored API key with delete permission for both related entities. |
GET /v1/exports/:exportJobId/download-url |
service-or-tenant-api-key |
Returns a signed artifact URL envelope without artifact bucket/key values, storage credentials, pause reason internals, filters, or object bodies. | Export download URL creation requires service credentials or a tenant-bound stored API key and blocks compliance-paused exports before returning a short-lived signed artifact URL envelope. |
GET /v1/exports/:exportJobId/progress |
service-or-tenant-api-key |
Returns export progress envelope (status, percent, rowCount) — no artifact URLs, no compliance-pause internals, no filters. | Export progress polling requires service credentials or a tenant-bound stored API key; the handler scopes lookups to the caller's tenant and never leaks artifact bucket/key details. |
POST /v1/devices/register |
service-token |
Persists device-bound push token. Stored token is hashed at rest; response contains only the registration id + masked token preview. | Mobile push-token registration requires a service credential (bearer/API-key) carrying user identity; the body's userId + tenantId are reconciled against the authenticated principal downstream. |
POST /v1/devices/revoke |
service-token |
Returns revocation confirmation without echoing the device token or push provider internals. | Mobile push-token revocation requires a service credential; the handler revokes by token hash and never echoes the raw token. |
GET /v1/entities/:entity |
service-token |
Returns legacy entity schema and relationship details. | Legacy entity lookup requires service credentials before returning the named entity detail graph. |
GET /status |
public-health |
Boolean health state and deployment region tag only — no connection strings, hostnames or stack traces. | Unauthenticated status probe for external uptime monitors. Returns boolean-only health, revision, region, uptime. |
GET /metrics |
service-token |
Prom text-format counters and gauges — includes business KPIs (AI tokens, mail, webhook, queue depth). Token-protected. | Prometheus scrape endpoint requires bearer METRICS_TOKEN. Returns 404 when METRICS_ENABLED is false. |
Verification Commands
Run focused verification from the repository root after changing Hono routes, OpenAPI security metadata, the typed route access inventory, or this document:
pnpm exec vitest run apps/api/src/route-access-inventory.test.ts apps/api/src/route-access-inventory-doc.test.ts
pnpm exec eslint apps/api/src/route-access-inventory.ts apps/api/src/route-access-inventory.test.ts apps/api/src/route-access-inventory-doc.test.ts --max-warnings=0
Expected diagnostics name stale or missing route keys in METHOD path form, OpenAPI security drift, redaction matches, and missing required section headings by heading text.