new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

Better Auth · Plugins · all subjects

organization plugin

107 notes in this subject, read out of this brain and free to use. This is page 1 of 2.

Organization plugin for team and member management

Better Auth includes an Organization plugin that provides organization, team, and member management.

Leave organization endpoint

POST /organization/leave (requires session, no result). Parameter: organizationId (string, required). Current user leaves the organization.

Update team endpoint

POST /organization/update-team (requires session). Parameters: teamId (string, required), data (object with optional name, organizationId, createdAt, updatedAt). Updates team details.

Remove team endpoint

POST /organization/remove-team. Parameters: teamId (string, required), organizationId (string, optional, defaults to active org). Deletes team from organization.

Member hooks: afterAddMember

Hook runs after a member is added. Receives { member, user, organization }. Used for sending welcome emails, creating default resources, etc.

Member hooks: beforeRemoveMember and afterRemoveMember

beforeRemoveMember receives { member, user, organization } for cleanup before removal. afterRemoveMember receives same params for logging after removal.

Update organization endpoint

POST /organization/update (requires session). Parameters: data (object with name, slug, logo, metadata properties, all optional), organizationId (string, optional). Updates organization information.

Organization plugin installation

Import organization from 'better-auth/plugins' and add it to the plugins array in betterAuth config. Run 'npx auth migrate' or 'npx auth generate' to add schema to the database. Then add organizationClient from 'better-auth/client/plugins' to the client config.

Create organization endpoint parameters

POST /organization/create (requires session). Parameters: name (string, default 'My Organization'), slug (string, default 'my-org'), logo (string | null, optional), metadata (Record<string, any>, optional), userId (string, optional, server-only, ignored if session headers provided), keepCurrentActiveOrganization (boolean, default false). Note: userId and session headers are mutually exclusive.

Restrict organization creation

Use allowUserToCreateOrganization option in organization plugin config. Pass a function that returns boolean or a boolean value directly. The function receives the user object and can check subscription plans or other conditions.

Check organization slug availability

POST /organization/check-slug endpoint. Parameter: slug (string, required). Returns whether the organization slug is taken or not.

Organization hooks: beforeCreateOrganization

Hook runs before organization is created. Receives { organization, user }. Can return { data: { ...organization, metadata: {...} } } to modify the organization data before creation.

Organization hooks: afterCreateOrganization

Hook runs after organization is created. Receives { organization, member, user }. Used for setup of default resources, sending notifications, etc. Does not return data.

Organization hooks: beforeUpdateOrganization

Hook runs before organization is updated. Receives { organization, user, member }. Can validate updates and apply business rules. Returns { data: {...} } to modify organization data.

Organization hooks: afterUpdateOrganization

Hook runs after organization is updated. Receives { organization, user, member }. Used to sync changes to external systems.

Member hooks: beforeAddMember

Hook runs before a member is added to an organization. Receives { member, user, organization }. Can validate or modify member data. Returns { data: { ...member, role: 'custom-role' } } to override the role.

Member hooks: beforeUpdateMemberRole

Hook runs before updating a member's role. Receives { member, newRole, user, organization }. Can validate role change permissions and throw APIError. Returns { data: { role: newRole } } to modify the role.

Member hooks: afterUpdateMemberRole

Hook runs after updating a member's role. Receives { member, previousRole, user, organization }. Used for logging role changes.

Invitation hooks: beforeCreateInvitation

Hook runs before creating an invitation. Receives { invitation, inviter, organization }. Can set custom expiration dates. Returns { data: { ...invitation, expiresAt: customDate } }.

Invitation hooks: afterCreateInvitation

Hook runs after creating an invitation. Receives { invitation, inviter, organization }. Used for sending custom invitation emails and tracking metrics.

Invitation hooks: beforeAcceptInvitation and afterAcceptInvitation

beforeAcceptInvitation receives { invitation, user, organization } for validation before acceptance. afterAcceptInvitation receives { invitation, member, user, organization } for setup after acceptance.

Invitation hooks: beforeRejectInvitation and afterRejectInvitation

beforeRejectInvitation receives { invitation, user, organization } for logging rejection reason. afterRejectInvitation receives same params for notifying inviter.

Invitation hooks: beforeCancelInvitation and afterCancelInvitation

beforeCancelInvitation receives { invitation, cancelledBy, organization } to verify cancellation permissions. afterCancelInvitation receives same params for logging.

Team hooks: beforeCreateTeam and afterCreateTeam

beforeCreateTeam receives { team, user, organization } to validate team names. Can return { data: { ...team, name: normalized } }. afterCreateTeam receives same params to create default team resources.

Team hooks: beforeUpdateTeam and afterUpdateTeam

beforeUpdateTeam receives { team, updates, user, organization } to validate updates. Returns { data: {...updates} }. afterUpdateTeam receives { team, user, organization } to sync to external systems.

Team hooks: beforeDeleteTeam and afterDeleteTeam

beforeDeleteTeam receives { team, user, organization } to backup team data. afterDeleteTeam receives same params to cleanup resources.

Team member hooks: beforeAddTeamMember and afterAddTeamMember

beforeAddTeamMember receives { teamMember, team, user, organization } to validate membership limits. afterAddTeamMember receives same params to grant access.

Team member hooks: beforeRemoveTeamMember and afterRemoveTeamMember

beforeRemoveTeamMember receives { teamMember, team, user, organization } to backup user's team data. afterRemoveTeamMember receives same params to revoke access.

Hook error handling in organization plugin

Throwing an error in a before hook will prevent the operation from proceeding. Can throw APIError('BAD_REQUEST', { message: 'error message' }). Use this for validation and permission checks.

useListOrganizations hook

Client hook to reactively get organizations the user is a member of. Returns { data: organizations, isPending: boolean }. Available for React, Vue, and Svelte.

List organizations endpoint

GET /organization/list (requires session). No parameters. Returns list of organizations the user is a member of.

Active organization concept

The workspace the user is currently working on. By default when user is signed in, active organization is null. Can be managed client-side only (different tabs can have different active organizations) or persisted in session.

Set active organization endpoint

POST /organization/set-active (requires session). Parameters: organizationId (string | null, optional), organizationSlug (string, optional). Can set to null to unset active organization.

Auto-set active organization on session creation

Use databaseHooks.session.create.before to set initial active organization. Implement custom logic to determine which organization to set as initial active organization.

useActiveOrganization hook

Client hook to retrieve active organization for user. Returns { data: activeOrganization, isPending: boolean }. Re-evaluates whenever active organization changes. Available for React, Vue, and Svelte.

Get organization endpoint

GET /organization/get-organization (requires session). Parameters: organizationId (string, optional), organizationSlug (string, optional). Gets organization metadata without members or invitations. Defaults to active organization if no params provided.

Get full organization endpoint

GET /organization/get-full-organization (requires session). Parameters: organizationId (string, optional), organizationSlug (string, optional), membersLimit (number, default 100). Returns full organization details including members. Defaults to active organization if no params provided.

Delete organization endpoint

POST /organization/delete (requires session). Parameter: organizationId (string, required). Deletes organization if user has owner role. Removes all members, invitations, and organization information. Can be disabled with disableOrganizationDeletion option.

Organization deletion hooks

beforeDeleteOrganization and afterDeleteOrganization hooks can be configured. beforeDeleteOrganization runs before deletion with access to ctx (endpoint context). afterDeleteOrganization runs after deletion.

sendInvitationEmail configuration

Required function in organization plugin config to send invitation emails. Receives data object with: id, email, inviter (with user object), organization. Must construct invite link with invitation ID for acceptInvitation call.

Send invitation endpoint

POST /organization/invite-member (requires session). Parameters: email (string, required), role (string | string[], required, can be 'admin', 'member', 'owner'), organizationId (string, optional, defaults to active org), resend (boolean, optional), teamId (string, optional). If user already member, invitation cancelled. If already invited and resend not true, not sent again.

Accept invitation endpoint

POST /organization/accept-invitation (requires session). Parameter: invitationId (string, required). User must be logged in with email matching invitation. Requires verified email by default unless requireEmailVerificationOnInvitation is false.

Email verification on invitation

By default, accepting invitation requires invitation ID and logged-in session with matching email. When invitation IDs are externally controlled or predictable (serial or custom generation), verified email is also required unless requireEmailVerificationOnInvitation set to false. Set to true for stricter security.

Cancel invitation endpoint

POST /organization/cancel-invitation (requires session, no result). Parameter: invitationId (string, required). Only inviter can cancel sent invitations.

Reject invitation endpoint

POST /organization/reject-invitation (requires session, no result). Parameter: invitationId (string, required). User can decline received invitation. Follows same email-verification policy as accepting invitations.

Get invitation endpoint

GET /organization/get-invitation (requires session). Parameter: id (string, required). Gets invitation details by ID. Follows same email-verification policy as accepting invitations.

List invitations endpoint

GET /organization/list-invitations (requires session). Parameter: organizationId (string, optional, defaults to active org). Lists all invitations for given organization. Response includes invitation IDs that are action-capable links. Treat as sensitive if unverified sessions can use them.

List user invitations client method

Call authClient.organization.listUserInvitations() to list all invitations for the current user. Requires session user's email to be verified on client side.

List user invitations server method

Call auth.api.listUserInvitations with query parameter email to list invitations for a specific user on the server. Email parameter only available server-side.

List members endpoint

GET /organization/list-members (requires session). Parameters: organizationId (string, optional, defaults to active org), limit (number, default 100), offset (number, default 0), sortBy (string, default 'createdAt'), sortDirection ('asc' | 'desc', default 'desc'), filterField (string, default 'createdAt'), filterOperator ('eq' | 'ne' | 'lt' | 'lte' | 'gt' | 'gte' | 'in' | 'not_in' | 'contains' | 'starts_with' | 'ends_with', default 'eq'), filterValue (string | number | boolean | string[] | number[]). Lists all members of organization with filtering and sorting.

Remove member endpoint

POST /organization/remove-member (requires session). Parameters: memberIdOrEmail (string, required, can be ID or email), organizationId (string, optional, uses active org if not provided). Removes member from organization.

Update member role endpoint

POST /organization/update-member-role (requires session, no result). Parameters: role (string | string[], required, can be single or multiple roles), memberId (string, required), organizationId (string, optional). Updates member's role(s).

Get active member role endpoint

GET /organization/get-active-member-role (requires session). No parameters. Returns user's member role in active organization as { role }.

Add member endpoint

POST /organization/add-member (server-only). Parameters: userId (string | null, optional), role (string | string[], required), organizationId (string, optional), teamId (string, optional). Adds member directly without invitation. userId can be null to use session headers.

Default organization roles

Three default roles: owner (created org, full control), admin (full control except can't delete org or change owner), member (limited control, can only read org data). A user can have multiple roles stored as comma-separated string.

Default organization permissions

organization resource: update, delete. member resource: create, update, delete. invitation resource: create, cancel. Owner has full control. Admin has full control except cannot delete org. Member has no control.

Create access control

Use createAccessControl function from 'better-auth/plugins/access'. Pass statement object with resource names as keys and arrays of actions as values. Use 'as const' for proper TypeScript inference.

Create custom roles with access control

Call ac.newRole() with permissions object to define custom roles. Each role specifies which resources and actions it can perform. Import defaultStatements and adminAc from 'better-auth/plugins/organization/access' to merge with existing permissions.

Pass custom roles to organization plugin

Pass ac (access controller) and roles object to organization plugin on both server and client. Server: betterAuth { plugins: [organization({ ac, roles: { owner, admin, member } })] }. Client: createAuthClient { plugins: [organizationClient({ ac, roles: { owner, admin, member } })] }.

Check permission with hasPermission

Server: auth.api.hasPermission({ headers: await headers(), body: { permissions: { project: ['create'] } } }). Client: authClient.organization.hasPermission({ permissions: { project: ['create'] } }). Can check multiple resource permissions at once.

Give your agent this brain