@dariomvg/create
auth0organizationsmulti-tenancynextjsintegracion

Módulo de Organizations con Auth0

Multi-tenancy para un proyecto de Next.js App Router usando Auth0 Organizations: crear/gestionar organizaciones, invitar y gestionar miembros, asignar roles básicos Owner/Admin/Member por organización, cambiar la organización activa y proteger Server Components según la pertenencia a una organización.

Este módulo es autocontenido (no importa nada del módulo de auth separado), pero asume que ese módulo (o uno equivalente) ya monta /auth/login y /auth/logout mediante su proxy.ts, ya que tanto el cambio de organización como la aceptación de invitaciones funcionan volviendo a autenticar a través de esa ruta.

Este módulo no implementa roles/permisos genéricos (RBAC): solo los roles fijos Owner/Admin/Member limitados a la pertenencia a una organización. Usá tu módulo separado de roles/permisos para cualquier cosa más allá de eso.

Dependencias

  • @auth0/nextjs-auth0 (^4.26.1 o más reciente)

Mapa de archivos

ArchivoDónde se usaPara qué sirve
types.tsen cualquier ladoTipos compartidos (Organization, OrganizationMember, Invitation, etc.)
service.tssolo internoCliente de la Management API, CRUD, invitaciones y asignación de roles. Nunca lo importes directamente.
actions.tsServer Components / Server Actions"use server" — el único punto de entrada del lado del servidor
client.tsClient ComponentsswitchOrganization, buildAcceptInvitationUrl
.env / .env.localraíz del proyectoVariables de entorno

Este módulo no incluye proxy.ts: solo puede existir un proxy por proyecto de Next.js, y tanto el cambio de organización como la aceptación de invitaciones reutilizan la ruta /auth/login que ya monta el proxy.ts del módulo de auth.

Uso

Listar y crear organizaciones

import { listUserOrganizations, createOrganization } from "@/lib/auth0-organizations/actions";

const orgs = await listUserOrganizations();
const created = await createOrganization({ name: "acme-inc", displayName: "Acme Inc." });

Proteger un Server Component según la organización activa

import { requireActiveOrganization } from "@/lib/auth0-organizations/actions";

export default async function TeamPage() {
  const org = await requireActiveOrganization("/organizations");
  return <p>You're viewing {org.displayName}</p>;
}

Selector de organización (Client Component)

"use client";
import { switchOrganization } from "@/lib/auth0-organizations/client";

export function OrgSwitcher({ organizations }: { organizations: { id: string; name: string }[] }) {
  return (
    <select onChange={(e) => switchOrganization(e.target.value)}>
      {organizations.map((o) => (
        <option key={o.id} value={o.id}>{o.name}</option>
      ))}
    </select>
  );
}

Invitar a un miembro

import { inviteMember } from "@/lib/auth0-organizations/actions";

await inviteMember({
  organizationId: org.id,
  email: "teammate@example.com",
  roles: ["member"],
  inviterName: "Jane (Acme Inc.)",
});

Aceptar / rechazar una invitación

Normalmente, aceptar es simplemente que el usuario invitado haga clic en el enlace del email de invitación: llega a /auth/login?organization=...&invitation=... y Auth0 completa el flujo automáticamente. acceptInvitation() en actions.ts es solo para una pantalla de confirmación personalizada antes de esa redirección.

import { declineInvitation } from "@/lib/auth0-organizations/actions";

await declineInvitation(organizationId, invitationId);

Cambiar el rol de un miembro

import { changeMemberRole } from "@/lib/auth0-organizations/actions";

await changeMemberRole(organizationId, userId, ["admin"]);

Configuración

Estos pasos se hacen en el Auth0 Dashboard: no tienen código.

  1. Habilitá Organizations en la aplicación: en tu Application → pestaña Organizations, elegí cómo debe comportarse el login: No Prompt, Prompt for organization o Require organization. "Require organization" es la opción más común para apps B2B multi-tenant.
  2. Creá los Roles: en User Management → Roles, creá tres roles con los nombres exactos Owner, Admin y Member (resolveRoleIds en service.ts compara sin distinguir mayúsculas, pero mantené los nombres consistentes). Definí los permisos/scopes de API que debería tener cada rol: este módulo solo asigna y lee asignaciones de roles, nunca define qué puede hacer un rol.
  3. Personalización del email de invitación: personalizá la plantilla en Branding → Email Templates → Organization Invitation si querés algo distinto al default de Auth0.
  4. Aplicación Machine-to-Machine: reutilizá la app M2M del módulo de auth (o creá una nueva) autorizada para la Auth0 Management API, con estos scopes: create:organizations, read:organizations, update:organizations, delete:organizations, create:organization_members, read:organization_members, delete:organization_members, create:organization_invitations, read:organization_invitations, delete:organization_invitations, create:organization_member_roles, read:organization_member_roles, delete:organization_member_roles y read:roles (se usa para resolver Owner/Admin/Member a sus Role IDs de Auth0).
  5. Conexiones específicas por organización (opcional): si distintas organizaciones deben usar distintas conexiones de login (por ejemplo, una org usa SSO de Google Workspace y otra usa email+contraseña), habilitá las conexiones correspondientes por organización en la pestaña Connections de cada una. No hace falta cambiar nada en este módulo para eso.