We just shipped add-mcp: think npx skills but for MCPs. One command to install MCPs across all your editors and agents

Organization

Manage multi-tenant organizations, members, and invitations

Beta

The Neon Auth with Better Auth is in Beta. Share your feedback on Discord or via the Neon Console.

Neon Auth is built on Better Auth and provides support for Organization plugin APIs through the Neon SDK. You do not need to manually install or configure the Better Auth Organization plugin.

The Organization plugin allows you to build multi-tenant applications where users can create workspaces, invite other members, and manage permissions using roles.

Preview Feature

The Organization plugin is currently in Beta. Support for invitation emails and JWT token claims is currently in progress.

Prerequisites

  • A Neon project with Auth enabled
  • A signed-in user (organizations are associated with users)

Organizations

Use the following methods to manage the organization lifecycle.

Create an organization

Creates a new organization. The user creating it automatically becomes the Owner.

View parameters
ParameterTypeRequiredNotes
namestring✓The display name of the organization
slugstring✓A URL-friendly identifier
logostring | undefinedOptional URL to a logo image for the organization
metadataRecord<string, any> | undefinedOptional JSON metadata for the organization
userIdstring | undefinedThe user ID of the organization creator
keepCurrentActiveOrganizationboolean | undefinedIf true, does not switch the active session to the new organization
const { data, error } = await authClient.organization.create({
  name: 'My Organization',
  slug: 'my-org',
  logo: 'https://example.com/logo.png',
  metadata: { plan: 'pro' },
  keepCurrentActiveOrganization: false,
});

Check organization slug

Checks if an organization slug is available.

View parameters
ParameterTypeRequiredNotes
slugstring✓The slug to check
const { data, error } = await authClient.organization.checkSlug({
  slug: 'my-org',
});

List organizations

Lists all organizations the current user is a member of.

View parameters

This method does not take any parameters.

const { data, error } = await authClient.organization.list();

In a React component, you can use the useListOrganizations hook to fetch and display organizations:

import { authClient } from './auth';

export default function OrganizationList() {
  const { data: organizations } = authClient.useListOrganizations();
  return (
    <div>
      {organizations?.map((org) => (
        <p>{org.name}</p>
      ))}
    </div>
  );
}

Set active organization

Switches the user's active context to a specific organization.

View parameters
ParameterTypeRequiredNotes
organizationIdstring | nullThe ID to set as active. Pass null to unset.
organizationSlugstring | undefinedAlternatively, pass the slug to set as active.
const { data, error } = await authClient.organization.setActive({
  organizationId: 'org_12345678',
});

Get active organization

Retrieves full details of the currently active organization.

View parameters
ParameterTypeRequiredNotes
organizationIdstring | undefinedOptional ID to get details for (defaults to active org)
organizationSlugstring | undefinedOptional slug to get details for
membersLimitnumber | undefinedLimit members returned in the response (default: 100)
const { data, error } = await authClient.organization.getFullOrganization({
  query: {
    organizationId: 'org-id',
    organizationSlug: 'org-slug',
    membersLimit: 10,
  },
});

In a React component, you can use the useActiveOrganization hook to fetch and display the active organization:

import { authClient } from './auth';

export default function ActiveOrganization() {
  const { data: organization } = authClient.useActiveOrganization();
  return (
    <div>
      <h1>{organization?.name}</h1>
      <p>Members: {organization?.members.length}</p>
    </div>
  );
}

Update organization

Updates organization details. Requires Owner or Admin permissions.

View parameters
ParameterTypeRequiredNotes
dataobject✓Object containing fields to update (name, slug, logo, metadata)
organizationIdstringThe ID of the organization to update
await authClient.organization.update({
  data: {
    name: 'New Name',
    metadata: { plan: 'enterprise' },
  },
  organizationId: 'org-id',
});

Delete organization

Deletes the organization and all associated data. Requires Owner permission.

View parameters
ParameterTypeRequiredNotes
organizationIdstring✓The ID of the organization to delete
const { data, error } = await authClient.organization.delete({
  organizationId: 'org-id',
});

Invitations

Manage invitations to join an organization.

Invitation Emails

Invitation emails are not sent during the Beta phase. They will be supported in a future release. In the meantime, users can accept invitations using the invitation ID or by viewing them in their invitation list.

Invite member

Sends an invitation to a user.

View parameters
ParameterTypeRequiredNotes
emailstring✓Email address to invite
rolestring✓Role to assign (owner, admin, member)
organizationIdstring | undefinedID of the organization (defaults to active org)
resendboolean | undefinedIf true, resends email if invitation already exists
const { data, error } = await authClient.organization.inviteMember({
  email: 'new-user@example.com',
  role: 'member',
  resend: true,
});

Accept invitation

Accepts an invitation using the invitation ID.

View parameters
ParameterTypeRequiredNotes
invitationIdstring✓The ID from the invitation link
const { data, error } = await authClient.organization.acceptInvitation({
  invitationId: 'invitation-id',
});

Reject invitation

Declines an invitation that the user has received and chooses not to accept.

View parameters
ParameterTypeRequiredNotes
invitationIdstring✓The ID of the invitation to reject
const { data, error } = await authClient.organization.rejectInvitation({
  invitationId: 'invitation-id',
});

Cancel invitation

Cancel a pending invitation that has been sent to a user.

View parameters
ParameterTypeRequiredNotes
invitationIdstring✓The ID of the invitation to cancel
const { data, error } = await authClient.organization.cancelInvitation({
  invitationId: 'invitation-id',
});

Get invitation

Retrieves details of a specific invitation.

View parameters
ParameterTypeRequiredNotes
query.idstring✓The ID of the invitation to retrieve
const { data, error } = await authClient.organization.getInvitation({
  query: {
    id: 'invitation-id',
  },
});

List invitations

Lists all pending invitations for an organization.

View parameters
ParameterTypeRequiredNotes
query.organizationIdstring | undefinedDefaults to the active organization
const { data, error } = await authClient.organization.listInvitations({
  query: {
    organizationId: 'org-id',
  },
});

List user invitations

Lists all invitations received by the current user.

View parameters

This method does not take any parameters.

const { data, error } = await authClient.organization.listUserInvitations();

Members

Manage users within the organization.

List members

Lists members with support for pagination, sorting, and filtering.

View parameters
ParameterTypeRequiredNotes
query.organizationIdstring | undefinedDefaults to the active organization
query.limitnumber | undefinedItems per page (default: 100)
query.offsetnumber | undefinedItems to skip
query.sortBystring | undefinedField to sort by (e.g., createdAt)
query.sortDirection"asc" | "desc" | undefinedSort direction
query.filterFieldstring | undefinedField to filter by
query.filterOperator"eq" | "ne" | "gt" | "contains" etc.Operator for filtering
query.filterValuestring | undefinedValue to filter for
const { data, error } = await authClient.organization.listMembers({
  query: {
    limit: 20,
    offset: 0,
    sortBy: 'createdAt',
    sortDirection: 'desc',
    filterField: 'role',
    filterOperator: 'eq',
    filterValue: 'admin',
  },
});

Update member role

Updates a member's role.

View parameters
ParameterTypeRequiredNotes
memberIdstring✓The ID of the member to update
rolestring| string[]✓New role(s) to assign (owner, admin, member)
organizationIdstring | undefinedDefaults to active organization
const { data, error } = await authClient.organization.updateMemberRole({
  memberId: 'member-id',
  role: 'admin',
});

Remove member

Removes a member from the organization.

View parameters
ParameterTypeRequiredNotes
memberIdOrEmailstring✓Member ID or Email address
organizationIdstring | undefinedDefaults to active organization
const { data, error } = await authClient.organization.removeMember({
  memberIdOrEmail: 'member-id-or-email',
});

Get active member

Gets the current user's membership details for the active organization.

View parameters

This method does not take any parameters.

const { data, error } = await authClient.organization.getActiveMember();

Get Active Member Role

Gets the current user's role(s) in the active organization.

View parameters

This method does not take any parameters.

const { data, error } = await authClient.organization.getActiveMemberRole();

Leave organization

Removes the current user from an organization.

View parameters
ParameterTypeRequiredNotes
organizationIdstring✓The ID of the organization to leave
const { data, error } = await authClient.organization.leave({
  organizationId: 'org-id',
});

Access Control

The Organization plugin includes a Role-Based Access Control (RBAC) system.

RolePermissions
OwnerFull control. Can delete the organization and manage all roles. The user who creates the organization is automatically assigned this role.
AdminCan invite members, update roles, and manage organization settings. Cannot delete the organization.
MemberRead-only access to organization data. Cannot manage other members.

You can check permissions on the client side using checkRolePermission:

const canDelete = authClient.organization.checkRolePermission({
  permission: {
    organization: ['delete'],
  },
  role: 'admin', // returns false, admins cannot delete orgs
});
// console.log(canDelete); // false

Limitations

Because Neon Auth is a managed service, some Better Auth features are not currently supported:

  • Teams: The Teams sub-feature is not currently enabled.
  • Hooks: Server-side hooks (e.g., beforeCreateOrganization) are not supported.
  • Custom Permissions: You cannot currently define custom roles or modify default permissions.
  • Dynamic Access Control: Dynamic creation of roles via API is not enabled.

Check the Neon Auth roadmap for updates on these features.

Need help?

Join our Discord Server to ask questions or see what others are doing with Neon. For paid plan support options, see Support.

Last updated on

Was this page helpful?