payload-plugin-masquerade
v1.4.3
Published
Masquerade user for Payload CMS
Maintainers
Readme
Payload Plugin Masquerade
The Masquerade plugin allows administrators to switch users and surf the site as that user (no password required). Administrators can switch back to their own user account at any time.

Table of Contents
- Features
- Requirements
- Installation
- Quick Start
- Configuration Options
- Admin UI
- API Endpoints
- Callbacks
- Security & Best Practices
- Development
- Troubleshooting
- Known Issues
- License
- Credits
Features
- ✅ Compatible with Payload v3 (^3.44.0)
- ✨ Zero external dependencies (only uses
uuid) - ⚙ Highly customizable with callbacks
- 🔒 Secure cookie-based authentication
- 🎯 Admin UI integration with user selection
- 📝 Audit trail support via callbacks
Requirements
- Node.js: >= 18
- Payload CMS: >= 3.44.0
Installation
Choose your package manager:
# pnpm
pnpm add payload-plugin-masquerade
# npm
npm install payload-plugin-masquerade
# yarn
yarn add payload-plugin-masqueradeQuick Start
Add the plugin to your Payload configuration:
import { masqueradePlugin } from 'payload-plugin-masquerade'
import { buildConfig } from 'payload'
export default buildConfig({
// ... your other config
plugins: [
masqueradePlugin({
// Optional: specify auth collection (defaults to 'users')
authCollection: 'users',
// Optional: enable/disable admin form (defaults to true)
enableBlockForm: true,
// Optional: enable/disable plugin (defaults to true)
enabled: true,
}),
],
})Configuration Options
| Option | Type | Default | Description |
| ----------------- | ---------- | ----------- | ------------------------------------------------------ |
| authCollection | string | 'users' | Slug of the collection used for authentication |
| enableBlockForm | boolean | true | Adds user selection block in Admin UI (beforeNavLinks) |
| enabled | boolean | true | Enables/disables the entire plugin |
| onMasquerade | function | undefined | Async callback called when starting masquerade |
| onUnmasquerade | function | undefined | Async callback called when ending masquerade |
Full Configuration Example
import { masqueradePlugin } from 'payload-plugin-masquerade'
export default buildConfig({
plugins: [
masqueradePlugin({
authCollection: 'users',
enableBlockForm: true,
enabled: true,
onMasquerade: async ({ req, masqueradeUserId }) => {
// req.user contains the original admin user
console.log(`Admin ${req.user?.email} started masquerading as user ${masqueradeUserId}`)
// Example: Log to audit collection
await req.payload.create({
collection: 'auditLogs',
data: {
action: 'masquerade_start',
adminId: req.user?.id,
targetUserId: masqueradeUserId,
timestamp: new Date(),
},
})
},
onUnmasquerade: async ({ req, originalUserId }) => {
// req.user contains the user we were masquerading as
console.log(`Ending masquerade, returning to user ${originalUserId}`)
// Example: Log audit trail
await req.payload.create({
collection: 'auditLogs',
data: {
action: 'masquerade_end',
adminId: originalUserId,
masqueradeUserId: req.user?.id,
timestamp: new Date(),
},
})
},
}),
],
})Admin UI
The plugin adds a user selection form to the admin interface that appears before the navigation links:

To disable the admin form:
masqueradePlugin({
enableBlockForm: false,
})API Endpoints
The plugin automatically adds these endpoints to your API:
Start Masquerade
GET /api/<authCollection>/:id/masqueradeBehavior:
- Creates a JWT token for the target user
- Sets Payload authentication cookie
- Sets
masqueradecookie with original user ID - Redirects to
/admin
Example:
curl -i "http://localhost:3000/api/users/USER_ID/masquerade"End Masquerade
GET /api/<authCollection>/unmasquerade/:idBehavior:
- Restores authentication to original user (ID from route)
- Clears
masqueradecookie - Redirects to
/admin
Example:
curl -i "http://localhost:3000/api/users/unmasquerade/ORIGINAL_USER_ID"Callbacks
onMasquerade
Called when masquerade session starts:
onMasquerade: async ({ req, masqueradeUserId }) => {
// req: PayloadRequest (req.user is the original admin)
// masqueradeUserId: ID of user being masqueraded
}onUnmasquerade
Called when masquerade session ends:
onUnmasquerade: async ({ req, originalUserId }) => {
// req: PayloadRequest (req.user is the masqueraded user)
// originalUserId: ID of the original admin user
}Security & Best Practices
⚠️ Security Warning: Masquerade functionality allows administrators to access user accounts without passwords. Follow these best practices:
- Restrict Access: Only grant masquerade permissions to trusted administrators
- Audit Trail: Use callbacks to log all masquerade activities:
onMasquerade: async ({ req, masqueradeUserId }) => { await req.payload.create({ collection: 'securityLogs', data: { action: 'masquerade', adminId: req.user?.id, targetId: masqueradeUserId, ipAddress: req.ip, userAgent: req.headers['user-agent'], timestamp: new Date(), }, }) } - Monitor Usage: Regularly review masquerade logs for suspicious activity
- Session Management: Masquerade sessions use the same timeout as regular sessions
Development
To contribute or run the plugin locally:
Clone the repository
git clone https://github.com/manutepowa/payload-plugin-masquerade.git cd payload-plugin-masqueradeInstall dependencies
pnpm installSet up development environment
cp dev/.env.example dev/.env # Edit dev/.env with your database configurationStart development servers
pnpm devVisit the admin Open http://localhost:3000/admin
Testing
# Run all tests
pnpm test
# Run integration tests only
pnpm test:int
# Run E2E tests only
pnpm test:e2eTroubleshooting
"The collection with the slug '...' was not found"
Cause: The authCollection option doesn't match any registered collection.
Solutions:
- Verify the collection slug matches exactly
- Ensure the collection is registered in
buildConfig.collections - Check that the plugin is loaded after the collection is defined
Masquerade UI not appearing
Cause: The enableBlockForm option might be disabled.
Solution:
masqueradePlugin({
enableBlockForm: true, // Make sure this is true
})Authentication issues after masquerade
Cause: Session conflicts or cookie issues.
Solutions:
- Clear browser cookies and try again
- Check that your auth collection uses the same session configuration
- Verify JWT signing key consistency
License
The MIT License (MIT). Please see License File for more information.
Credits
- This package was inspired by the Drupal Masquerade module
- Maintained by manutepowa
