better-auth-organization-member

raw JSON →
1.0.9 verified Sat Apr 25 auth: no javascript

A Better Auth plugin that extends the organization plugin with member update capabilities and automatic hook injection for invitation-to-member data transfer. Version 1.0.9 requires better-auth >= 1.4.9 and the organization plugin. Ships TypeScript types, supports additional fields (firstName, lastName, avatar, custom) with full type inference via inferOrgMemberAdditionalFields. Key differentiators: no manual hooks, automatic afterAcceptInvitation hook injection, lifecycle hooks for before/after update, and both server and client packages.

error ERR_REQUIRE_ESM
cause Using require() on ESM-only package better-auth-organization-member
fix
Change to import statement or use dynamic import(). Also ensure 'type': 'module' in package.json
error TypeError: Cannot read properties of undefined (reading 'additionalFields')
cause organizationMember plugin not added after organization plugin, or organization plugin missing schema
fix
Add organization plugin before organizationMember, and define schema for member.additionalFields if using custom fields
error Module not found: Error: Can't resolve 'better-auth-organization-member/client'
cause Missing installation or incorrect path; package must be installed
fix
Run npm install better-auth-organization-member. If using TypeScript, ensure moduleResolution is set to bundler or node16
error TypeScript error: Type '{}' is not assignable to type 'InferOrgMemberAdditionalFields<AuthType>'
cause Passing auth object type incorrectly; inferOrgMemberAdditionalFields expects a generic type parameter
fix
Use inferOrgMemberAdditionalFields<typeof auth>() properly; ensure auth is exported as a type
error Error: afterAcceptInvitation hook already exists
cause Manually defining afterAcceptInvitation hook in organization plugin conflicts with automatic injection
fix
Remove manually defined afterAcceptInvitation hook from organization plugin config; let organizationMember handle it
gotcha organizationMember plugin must be added after the organization plugin; else hook injection may fail or cause unexpected behavior
fix Ensure organization plugin is listed first in the plugins array, then organizationMember
gotcha Client plugin (organizationMemberClient) must import from 'better-auth-organization-member/client', not the main package; main package does not export client functions
fix Use import { organizationMemberClient } from 'better-auth-organization-member/client'
gotcha Type inference helper inferOrgMemberAdditionalFields requires TypeScript and the auth object type to be imported; if auth type is not available, schema must be defined manually
fix Either import type { auth } from './auth' and pass to generic, or define schema object manually
breaking Plugin is ESM-only; CommonJS require() will fail with ERR_REQUIRE_ESM
fix Use dynamic import() or switch project to ESM; set 'type': 'module' in package.json
deprecated Node engines specified >=22; older Node versions will fail to install or run
fix Upgrade Node to version 22 or later
npm install better-auth-organization-member
yarn add better-auth-organization-member
pnpm add better-auth-organization-member

Shows server and client setup with custom additional fields, automatic hook injection, and member update call.

import { betterAuth } from 'better-auth';
import { organization } from 'better-auth/plugins';
import { organizationMember } from 'better-auth-organization-member';

export const auth = betterAuth({
  plugins: [
    organization({
      schema: {
        member: {
          additionalFields: {
            firstName: { type: 'string', input: true, required: false },
            lastName: { type: 'string', input: true, required: false },
            avatar: { type: 'string', input: true, required: false },
          },
        },
        invitation: {
          additionalFields: {
            firstName: { type: 'string', input: true, required: false },
            lastName: { type: 'string', input: true, required: false },
            avatar: { type: 'string', input: true, required: false },
          },
        },
      },
    }),
    organizationMember({
      schema: {
        member: {
          additionalFields: {
            firstName: { type: 'string', input: true, required: false },
            lastName: { type: 'string', input: true, required: false },
            avatar: { type: 'string', input: true, required: false },
          },
        }
      },
      organizationMemberHooks: {
        async beforeUpdateMember(data) {
          return { data: { ...data.updates } };
        },
      },
    }),
  ],
});

// Client setup
import { createAuthClient } from 'better-auth/client';
import { organizationClient } from 'better-auth/client/plugins';
import { organizationMemberClient, inferOrgMemberAdditionalFields } from 'better-auth-organization-member/client';
import type { auth } from './auth';

const client = createAuthClient({
  plugins: [
    organizationClient({
      schema: inferOrgMemberAdditionalFields<typeof auth>()
    }),
    organizationMemberClient({
      schema: inferOrgMemberAdditionalFields<typeof auth>()
    })
  ],
});

// Update member
await client.organization.updateMember({
  memberId: 'member-id',
  data: {
    role: 'admin',
    firstName: 'Jane',
    lastName: 'Doe',
    avatar: 'https://example.com/avatar.png'
  }
});