Skip to main content
The invite plugin supports custom token generation, allowing you to implement your own token format and generation logic.

Token Types

The plugin provides three token types:

Token

24-character secure ID

Code

6-character alphanumeric code

Custom

Your own implementation

Built-in Token Generators

The plugin uses these default generators from src/utils.ts:68-83:

Token Type

Generates a 24-character ID using Better Auth’s generateId function.
invite({
  defaultTokenType: 'token'
})
Example output: a1b2c3d4e5f6g7h8i9j0k1l2

Code Type

Generates a 6-character alphanumeric code using uppercase letters and numbers.
invite({
  defaultTokenType: 'code'
})
Example output: A1B2C3 Implementation:
generateRandomString(6, "0-9", "A-Z")

Custom Token Implementation

To implement custom token generation, set defaultTokenType to 'custom' and provide a generateToken function.

Basic Example

import { invite } from 'better-auth-invite-plugin';

export const auth = betterAuth({
  plugins: [
    invite({
      defaultTokenType: 'custom',
      generateToken: () => {
        return crypto.randomUUID();
      }
    })
  ]
});

UUID Tokens

Generate RFC 4122 compliant UUIDs:
invite({
  defaultTokenType: 'custom',
  generateToken: () => {
    return crypto.randomUUID();
  }
})
Example output: 550e8400-e29b-41d4-a716-446655440000

Nanoid Tokens

Use nanoid for short, URL-safe tokens:
import { nanoid } from 'nanoid';

invite({
  defaultTokenType: 'custom',
  generateToken: () => {
    return nanoid(16);
  }
})
Example output: V1StGXR8_Z5jdHi6

Prefixed Tokens

Add prefixes to identify token types:
import { generateId } from 'better-auth';

invite({
  defaultTokenType: 'custom',
  generateToken: () => {
    return `inv_${generateId(20)}`;
  }
})
Example output: inv_a1b2c3d4e5f6g7h8i9j0

Timestamp-based Tokens

Include timestamps in your tokens:
import { generateId } from 'better-auth';

invite({
  defaultTokenType: 'custom',
  generateToken: () => {
    const timestamp = Date.now().toString(36);
    const random = generateId(12);
    return `${timestamp}_${random}`;
  }
})
Example output: lm3x9g_a1b2c3d4e5f6

Token Resolution

The resolveTokenGenerator function from src/utils.ts:68-83 determines which generator to use:
export const resolveTokenGenerator = (
  tokenType: TokensType,
  options: NewInviteOptions,
): (() => string) => {
  if (tokenType === 'custom' && options.generateToken) {
    return options.generateToken;
  }

  const tokenGenerators: Record<TokensType, () => string> = {
    code: () => generateRandomString(6, "0-9", "A-Z"),
    token: () => generateId(24),
    custom: () => generateId(24), // secure fallback
  };

  return tokenGenerators[tokenType];
};
If you set defaultTokenType: 'custom' without providing generateToken, the system falls back to the default token generator for security.

Per-Invite Token Types

You can override the default token type when creating individual invites:
const { data } = await authClient.invite.create({
  email: '[email protected]',
  role: 'member',
  tokenType: 'code' // Override default
});
This allows mixing token types in the same application.

Security Considerations

Token Uniqueness

Ensure your custom generator produces unique tokens. The database schema enforces uniqueness at src/schema.ts:6:
token: { type: "string", unique: true }

Token Length

Generate tokens with sufficient entropy:
Tokens shorter than 16 characters may be vulnerable to brute force attacks.
Recommended minimum:
  • Random tokens: 20-24 characters
  • UUIDs: Use standard format (36 characters with hyphens)
  • Codes: 6-8 characters (uppercase alphanumeric)

Cryptographic Security

Use cryptographically secure random number generators:
import { generateId } from 'better-auth';
import { generateRandomString } from 'better-auth/crypto';
import { nanoid } from 'nanoid';

// All of these are cryptographically secure
generateId(24);
generateRandomString(6, "0-9", "A-Z");
nanoid(16);
crypto.randomUUID();

Token Expiration

Custom tokens follow the same expiration rules defined in your configuration:
invite({
  defaultTokenType: 'custom',
  generateToken: () => crypto.randomUUID(),
  invitationTokenExpiresIn: 60 * 60 // 1 hour
})
See Security for more details on token expiration and security features.

Advanced Patterns

Context-Aware Tokens

While the generateToken function doesn’t receive parameters, you can use closures to access context:
let currentRole: string | null = null;

invite({
  defaultTokenType: 'custom',
  generateToken: () => {
    const prefix = currentRole ? currentRole.substring(0, 3) : 'inv';
    return `${prefix}_${generateId(20)}`;
  },
  inviteHooks: {
    beforeCreateInvite: async ({ ctx }) => {
      // This is a workaround - the API doesn't pass role to generateToken
      // currentRole = inviteData.role;
    }
  }
})
This pattern has limitations since generateToken doesn’t receive invite data. Use with caution.

Database-Backed Tokens

Generate tokens that check for uniqueness:
import { nanoid } from 'nanoid';

invite({
  defaultTokenType: 'custom',
  generateToken: () => {
    // Generate token
    // Note: The plugin will handle database uniqueness constraint
    return nanoid(16);
  }
})
The database unique constraint at src/schema.ts:6 ensures no duplicate tokens exist.

Testing Custom Tokens

Test your custom token generator:
import { describe, it, expect } from 'vitest';

const generateToken = () => {
  return crypto.randomUUID();
};

describe('Custom token generator', () => {
  it('generates unique tokens', () => {
    const token1 = generateToken();
    const token2 = generateToken();
    
    expect(token1).not.toBe(token2);
  });
  
  it('generates tokens with correct format', () => {
    const token = generateToken();
    
    // UUID format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
    expect(token).toMatch(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/);
  });
  
  it('generates tokens with sufficient length', () => {
    const token = generateToken();
    
    expect(token.length).toBeGreaterThanOrEqual(16);
  });
});

Build docs developers (and LLMs) love