@purposeinplay/cms-plugins
v1.0.3
Published
Payload CMS plugins: audit-log and TOTP 2FA
Downloads
388
Keywords
Readme
@purposeinplay/cms-plugins
Payload CMS plugins for audit logging and TOTP two-factor authentication.
Installation
pnpm add @purposeinplay/cms-pluginsPlugins
Audit Log
Immutable audit trail for collection/global CRUD operations and login events.
// payload.config.ts
import { auditLogPlugin } from '@purposeinplay/cms-plugins/audit-log';
export default buildConfig({
plugins: [
auditLogPlugin({
collections: ['users', 'posts', 'media'],
globals: ['site-config'],
trackLogin: true,
retention: { days: 90 },
}),
],
});Options:
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| collections | string[] | [] | Collection slugs to track |
| globals | string[] | [] | Global slugs to track |
| trackLogin | boolean | true | Log login events |
| retention | { days: number } \| false | { days: 90 } | Auto-delete old entries |
| collectionSlug | string | 'audit-logs' | Audit collection slug |
| authCollectionSlug | string | 'users' | Auth collection slug |
| allowCascading | boolean | false | Log cascading relationship updates |
| excludeFields | string[] | [] | Additional fields to exclude from diffs |
| jsonMaxBytes | number | 524288 | Max JSON size for snapshots (512 KB) |
| access.read | Access | admin-only | Custom read access control |
| titleFieldMap | Record<string, string> | {} | Custom title field per collection |
TOTP (Two-Factor Authentication)
RFC 6238-compliant TOTP 2FA with encrypted secrets, backup codes, and rate limiting.
// payload.config.ts
import { totpPlugin } from '@purposeinplay/cms-plugins/totp';
export default buildConfig({
plugins: [
totpPlugin({
forceSetup: true,
}),
],
});// middleware.ts (or proxy.ts)
import { handleTOTPMiddleware } from '@purposeinplay/cms-plugins/totp/middleware';
export default async function middleware(request: NextRequest) {
const totpResponse = await handleTOTPMiddleware(request);
if (totpResponse) return totpResponse;
return NextResponse.next();
}// app/(payload)/admin/layout.tsx
import { TOTPGate, TOTPGuard } from '@purposeinplay/cms-plugins/totp/guard';
import configPromise from '@payload-config';
export default function AdminLayout({ children }) {
return (
<TOTPGuard config={configPromise}>
<TOTPGate>{children}</TOTPGate>
</TOTPGuard>
);
}Environment Variables:
| Variable | Required | Description |
|----------|----------|-------------|
| TOTP_ENCRYPTION_KEY | Yes | 32-byte hex key for AES-256-GCM encryption of TOTP secrets |
| PAYLOAD_SECRET | Yes | Standard Payload secret (used for cookie HMAC signing) |
Generate encryption key: node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
Plugin Options:
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| forceSetup | boolean | true | Force non-admin users to enable 2FA |
| authCollectionSlug | string | 'users' | Auth collection slug |
| backupCodeCount | number | 10 | Number of backup codes |
| cookieMaxAge | number | 28800 | Verified cookie lifetime (seconds) |
| pendingCookieMaxAge | number | 300 | Pending cookie lifetime (seconds) |
| encryptionKey | string | env var | Override TOTP_ENCRYPTION_KEY |
| tokenExpiration | string | '7d' | JWT expiry duration |
| rateLimit.maxFailures | number | 5 | Max failed attempts before lockout |
| rateLimit.lockoutMs | number | 900000 | Lockout duration (15 min) |
| rateLimit.windowMs | number | 60000 | Sliding failure window (1 min) |
| onAuditEvent | function | undefined | Audit event callback |
| enabled | boolean | true | Enable/disable plugin |
Exports
| Subpath | Exports |
|---------|---------|
| @purposeinplay/cms-plugins/audit-log | auditLogPlugin, AuditLogEntry, AuditLogPluginOptions, ChangeFormatterOptions |
| @purposeinplay/cms-plugins/totp | totpPlugin, TOTPPluginOptions, TOTPAuditEvent, TOTPSecret, UserForGuard, UserForToken, handleTOTPMiddleware, getTOTPRedirectPath, defaults |
| @purposeinplay/cms-plugins/totp/client | SetupTOTPView, VerifyTOTPView |
| @purposeinplay/cms-plugins/totp/middleware | handleTOTPMiddleware |
| @purposeinplay/cms-plugins/totp/guard | TOTPGuard, TOTPGate, getTOTPRedirectPath |
| @purposeinplay/cms-plugins/totp/testing | Test utilities: createPendingCookieValueForTesting, verifyPendingCookie, createTOTPVerifiedCookieValue, getTOTPVerifiedCookieName, createPayloadToken |
Peer Dependencies
| Package | Required For |
|---------|-------------|
| payload@^3.0.0 | Both plugins |
| @payloadcms/ui@^3.0.0 | TOTP admin views (optional) |
| @payloadcms/db-postgres@^3.0.0 | TOTP rate limiting (optional) |
| next@^15 \|\| ^16 | TOTP middleware/guard (optional) |
| react@^18 \|\| ^19 | TOTP client components (optional) |
| react-dom@^18 \|\| ^19 | TOTP client components (optional) |
Tailwind CSS
If using TOTP client components, add the package to your Tailwind content config:
content: ['./node_modules/@purposeinplay/cms-plugins/dist/**/*.js']Development
pnpm install
pnpm build # Build dist/
pnpm dev # Watch mode
pnpm test # Run tests
pnpm test:watch # Watch mode testsPublishing
pnpm build && npm publish --access restricted