Organizations

Organizations let your end-users create and manage multi-tenant workspaces inside your product. Each organization has members with roles, and roles carry permissions you define.


How it works

An organization is a group of end-users that share access to resources in your application. AuthGate manages the full lifecycle — creation, membership, invitations, and permission checks — so you don't have to build multi-tenancy infrastructure from scratch.

  • Every organization has a unique ID and an optional slug (human-readable URL segment)
  • Members belong to an organization through a membership record that links a user, an organization, and a role
  • Roles carry permissions defined as resource:action strings (e.g. documents:write)
  • Invitations are time-limited (7 days) and accepted via a one-time token

See Roles & Permissions for how to define roles and permission strings, and Organizations SDK for the full SDK reference.


Creating organizations

Organizations are created by end-users through your application. Call the proxy API or use the AuthGateClient from @auth-gate/core.

Via the proxy API

Create organization

curl -X POST https://your-authgate-instance.com/api/proxy/orgs \
  -H "Authorization: Bearer <user_jwt>" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Acme Corp",
    "slug": "acme-corp"
  }'

Response

{
  "org": {
    "id": "org_abc123",
    "name": "Acme Corp",
    "slug": "acme-corp",
    "created_at": "2025-01-15T10:00:00Z"
  }
}

The user who creates the organization is automatically added as a member with the default admin role.

Via the SDK

src/app/api/orgs/route.ts

import { createAuthGate } from "@auth-gate/nextjs";

const { client } = createAuthGate({
  apiKey: process.env.AUTHGATE_API_KEY!,
  baseUrl: process.env.AUTHGATE_URL!,
  appUrl: process.env.NEXT_PUBLIC_APP_URL!,
});

export async function POST(request: Request) {
  const { name, slug } = await request.json();
  const org = await client.createOrg({ name, slug });
  return Response.json({ org });
}

Listing organizations

List orgs for the current user

import { AuthGateClient } from "@auth-gate/core";

const client = new AuthGateClient({
  baseUrl: process.env.AUTHGATE_URL!,
  userToken: userJwt,
});

const { organizations } = await client.listOrgs();

Each entry in organizations is an OrgWithMembership — it includes the org details and the calling user's membership record (role and permissions).


Managing members

Adding a member

Add a user directly to an organization via the admin API. This is useful for programmatic onboarding flows where you don't need the invitation email flow.

Add member (admin API)

import { AuthGateClient } from "@auth-gate/core";

const adminClient = new AuthGateClient({
  baseUrl: process.env.AUTHGATE_URL!,
  apiKey: process.env.AUTHGATE_API_KEY!,
});

await adminClient.addOrgMember("org_abc123", {
  userId: "user_xyz",
  roleKey: "member",
});

Changing a member's role

Update member role

await client.updateOrgMember("org_abc123", "user_xyz", {
  roleKey: "admin",
});

Removing a member

Remove member

await client.removeOrgMember("org_abc123", "user_xyz");

Leaving an organization

Members can leave an organization themselves:

Leave org

await client.leaveOrg("org_abc123");

Invitations

Invite users to an organization by email. AuthGate sends the invitation email and manages the token lifecycle.

Sending an invitation

Invite by email

const { invitation } = await client.inviteToOrg("acme-corp", {
  email: "alice@example.com",
  roleKey: "member",
});

Invitation object

{
  "id": "inv_abc123",
  "email": "alice@example.com",
  "role": { "key": "member", "name": "Member" },
  "expires_at": "2025-01-22T10:00:00Z",
  "created_at": "2025-01-15T10:00:00Z"
}

Invitations expire after 7 days. The invited user receives an email with a link containing a one-time accept token.

Accepting an invitation

When the user clicks the invitation link, exchange the token for membership:

Accept invitation

const { membership } = await client.acceptOrgInvitation({
  token: "inv_token_from_url",
});

The user must be authenticated before accepting. If they don't have an account, prompt them to sign up first.

Managing pending invitations

List and revoke invitations

// List pending invitations for an org
const { invitations } = await client.listOrgInvitations("acme-corp");

// Revoke a specific invitation
await client.revokeOrgInvitation("acme-corp", "inv_abc123");

Permissions

Check whether the current user has a specific permission before performing sensitive actions.

Using SDK utilities

Check permissions server-side

import { hasPermission, hasRole, hasAnyPermission } from "@auth-gate/core";
import { createOrgHelpers } from "@auth-gate/nextjs";

const { getOrgMembership } = createOrgHelpers({
  baseUrl: process.env.AUTHGATE_URL!,
  apiKey: process.env.AUTHGATE_API_KEY!,
});

export async function deleteDocument(orgId: string, userId: string) {
  const membership = await getOrgMembership(orgId, userId);

  if (!hasPermission(membership, "documents:delete")) {
    throw new Error("Insufficient permissions");
  }

  // proceed with deletion
}

Using React hooks and components

Gate UI by permission

import { OrgGuard } from "@auth-gate/react";

function ManageTeamButton({ orgId }: { orgId: string }) {
  return (
    <OrgGuard orgId={orgId} permission="org:manage" fallback={null}>
      <button>Manage Team</button>
    </OrgGuard>
  );
}

See Roles & Permissions for the full permission string format and Organizations SDK for the complete SDK reference.

Was this page helpful?