X Enterprises
nuxt-x-tenancy

Backend requirements

What the backend must provide for nuxt-x-tenancy — the better-auth organization endpoints, the tenant id contract, and the X-Tenant-ID data-API contract.

Backend requirements

What the backend must provide for nuxt-x-tenancy to work. The layer ships no server code; it composes nuxt-x-auth-better on the identity side and expects a tenant-aware API on the data side. This page summarizes the package's BACKEND-REQUIREMENTS.md — read that file in the repo for the authoritative contract.

1. Identity: better-auth with the organization plugin

The consumer runs a better-auth server with the organization plugin enabled (see nuxt-x-auth-better's integration guide). The layer uses exactly these client endpoints:

EndpointUsed for
GET {baseUrl}{authPath}/get-sessionSession + session.activeOrganizationId
GET {baseUrl}{authPath}/organization/listtenants + slug → org resolution (resolveBySlug)
GET {baseUrl}{authPath}/organization/get-full-organizationActive tenant (no params — returns the session's active org)
POST {baseUrl}{authPath}/organization/set-activeswitchTenant(id)
GET {baseUrl}{authPath}/organization/get-active-member(via auth-better) member role
Slugs are resolved against the organization/list response, notget-full-organization?organizationSlug= — better-auth's client (≤1.6.5) drops that method's GET query params, so server-side slug lookup is unreliable. See Resolution chain.

2. ID contract

tenant id === better-auth organization id. The layer never mints its own ids. Per-tenant rows in any backend should key on the organization id, so nuxt-x-app-admin's per-tenant views and this layer's X-Tenant-ID header refer to the same identifier without translation.

3. Data API: the X-Tenant-ID header

Tenant-scoped API endpoints must:

  1. Read the tenant id from the X-Tenant-ID request header (name configurable via xTenancy.headerName).
  2. Authorize: the session user must be a member of that organization — the header is a selector, never a proof of membership.
  3. Filter all rows by that tenant id.

The layer injects the header client-side into every $fetch request that doesn't already set it (opt out: xTenancy.injectHeader: false), and exposes $tenantHeaders() for SSR/custom clients. Requests without the header should be treated as unscoped — reject or return nothing for tenant-scoped resources; never fall back to "all tenants".

4. Subdomain strategy (optional)

When xTenancy.strategy: 'subdomain': wildcard DNS / vhost for *.{rootDomain} routes to the Nuxt app; the left-most host label is the organization slug, activated via the standard set-active endpoint. No extra backend work beyond §1.


AI Context

guide: backend-requirements
package: "@xenterprises/nuxt-x-tenancy"
use-when: >
  Implementing the backend for a tenancy consumer. better-auth with the
  organization plugin for identity; tenant id === organization id; data
  APIs read X-Tenant-ID (selector, not proof of membership) and filter
  rows by it. Subdomain strategy needs only wildcard DNS.
Copyright © 2026