npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@authhero/multi-tenancy

v14.10.0

Published

Multi-tenancy support for AuthHero with organization-based access control and per-tenant database isolation

Readme

@authhero/multi-tenancy

Multi-tenancy support for AuthHero with organization-based access control, per-tenant database isolation, and subdomain routing.

Features

  • 🔐 Organization-based Access Control - Control tenant access via JWT tokens with org_id claims
  • 💾 Database Isolation - Per-tenant databases with D1, Turso, or custom providers
  • ⚙️ Settings Inheritance - Inherit configuration from main tenant to child tenants
  • 🌐 Subdomain Routing - Automatic subdomain-to-tenant resolution
  • 🔄 Tenant Lifecycle - Automated provisioning and deprovisioning
  • 🪝 Composable Architecture - Combine multi-tenancy features with the base AuthHero package
  • 📡 Entity Sync - Automatically sync resource servers, roles, and connections from control plane to all child tenants

Installation

pnpm add authhero @authhero/multi-tenancy

::: tip Peer Dependency @authhero/multi-tenancy requires authhero as a peer dependency. Both packages must be installed. :::

Documentation

📚 Full documentation: https://authhero.net/packages/multi-tenancy/

Quick Start

import { initMultiTenant } from "@authhero/multi-tenancy";
import createAdapters from "@authhero/kysely-adapter";

const dataAdapter = createAdapters(db);

const { app } = initMultiTenant({
  dataAdapter,
  // That's it! Everything else has sensible defaults:
  // - controlPlaneTenantId: "control_plane"
  // - Resource servers, roles, and connections sync enabled
  // - Tenants API mounted at /tenants
  // - Protected synced entities middleware applied
});

export default app;

Customization

const { app } = initMultiTenant({
  dataAdapter,
  controlPlaneTenantId: "main",
  sync: {
    resourceServers: true,
    roles: true,
    connections: false, // Don't sync connections
  },
  defaultPermissions: ["tenant:admin", "tenant:read"],
});

Advanced Setup

For more control, use the lower-level APIs:

import { init, fetchAll } from "authhero";
import {
  createSyncHooks,
  createTenantsOpenAPIRouter,
  createProtectSyncedMiddleware,
} from "@authhero/multi-tenancy";

const { entityHooks, tenantHooks } = createSyncHooks({
  controlPlaneTenantId: "control_plane",
  getChildTenantIds: async () => {
    /* ... */
  },
  getAdapters: async () => dataAdapter,
  getControlPlaneAdapters: async () => dataAdapter,
});

const tenantsRouter = createTenantsOpenAPIRouter(
  { accessControl: { controlPlaneTenantId: "control_plane" } },
  { tenants: tenantHooks },
);

const { app } = init({
  dataAdapter,
  entityHooks,
  managementApiExtensions: [{ path: "/tenants", router: tenantsRouter }],
});

app.use("/api/v2/*", createProtectSyncedMiddleware());

Key Concepts

Organization-Tenant Model

Organizations on a "main" tenant represent and control access to child tenants. Each organization maps to one child tenant.

Token-Based Access

Access is controlled via the org_id claim in JWT tokens:

  • No org_id: Main tenant only
  • With org_id: Access to matching tenant

Silent Authentication

Switch tenants by requesting a new token with a different organization:

const token = await getAccessTokenSilently({
  authorizationParams: {
    organization: "tenant-id",
  },
});

Resource Server Synchronization

Automatically sync resource servers (APIs) from the main tenant to all child tenants. When you create, update, or delete a resource server on the main tenant, it's automatically propagated to all other tenants.

import { createResourceServerSyncHooks } from "@authhero/multi-tenancy";

const resourceServerHooks = createResourceServerSyncHooks({
  mainTenantId: "main",
  getChildTenantIds: async () => {
    // Return all tenant IDs except the main tenant
    const { tenants } = await adapters.tenants.list();
    return tenants.filter((t) => t.id !== "main").map((t) => t.id);
  },
  getAdapters: async (tenantId) => {
    // Return adapters for the target tenant
    return createAdaptersForTenant(tenantId);
  },
  // Optional: filter which resource servers to sync
  shouldSync: (resourceServer) => {
    // Only sync resource servers that start with "api:"
    return resourceServer.identifier.startsWith("api:");
  },
});

// Use with AuthHero config
const config: AuthHeroConfig = {
  dataAdapter,
  entityHooks: {
    resourceServers: [resourceServerHooks],
  },
};

Migration Guide

Migrating from Legacy Settings Inheritance

If you're using the deprecated settings inheritance functions, migrate to the new runtime fallback API:

Before (Deprecated)

import {
  withSettingsInheritance,
  SettingsInheritanceConfig,
} from "@authhero/multi-tenancy";

const config: SettingsInheritanceConfig = {
  controlPlaneTenantId: "main",
  controlPlaneClientId: "main-client",
};

const adapters = withSettingsInheritance(baseAdapters, config);

After (Current)

import {
  withRuntimeFallback,
  RuntimeFallbackConfig,
} from "@authhero/multi-tenancy";

const config: RuntimeFallbackConfig = {
  controlPlaneTenantId: "main",
  controlPlaneClientId: "main-client",
};

const adapters = withRuntimeFallback(baseAdapters, config);

What changed:

  • withSettingsInheritancewithRuntimeFallback
  • createSettingsInheritanceAdaptercreateRuntimeFallbackAdapter
  • SettingsInheritanceConfigRuntimeFallbackConfig

The functionality remains identical - this is purely a naming change to better reflect that settings are inherited at runtime without copying data between tenants.

License

MIT