WorkOS OAuth plugin for Payload CMS v3 - adds Google OAuth login to your Payload admin panel
npm install payload-workos-oauthWorkOS OAuth plugin for Payload CMS - adds Google OAuth login to your Payload admin panel.
> Version 2.0.0+ supports Payload CMS v3.72.0+
> For Payload v2, use v1.x
- 🔐 Google OAuth authentication via WorkOS
- 🎨 Clean, customizable login button
- 🔒 Admin-only access control
- 🍪 JWT-based authentication with secure cookies
- ⚡ No session middleware required
- 🎯 Easy integration with existing Payload CMS projects
- 🎭 Optional: Hide default email/password login form
``bash`
npm install payload-workos-oauth@^2.0.0
`bash`
npm install payload-workos-oauth@^1.0.0
1. A WorkOS account
2. Google OAuth configured in your WorkOS dashboard
3. Payload CMS v3.72.0 or higher (or v2.0.0+ for v1.x of this plugin)
`typescript
import { buildConfig } from "payload";
import { workosOAuthPlugin } from "payload-workos-oauth";
export default buildConfig({
// ... other config
serverURL: process.env.PAYLOAD_PUBLIC_SERVER_URL,
admin: {
components: {
// Add the OAuth button to the login page
beforeLogin: ["payload-workos-oauth/BeforeLogin"],
},
},
plugins: [
workosOAuthPlugin({
clientID: process.env.WORKOS_CLIENT_ID || "",
clientSecret: process.env.WORKOS_API_KEY || "",
callbackURL: ${process.env.PAYLOAD_PUBLIC_SERVER_URL}/workos-oauth/callback,`
}),
],
});
Important for Payload v3: You must add the BeforeLogin component to your admin.components.beforeLogin array as shown above. This is required for the button to appear on the login page.
After adding the component to your config, you must regenerate Payload's import map:
`bash`
npm run generate:importmapor
pnpm generate:importmapor
yarn generate:importmap
This step is required for the button to appear on the login page.
`bash`
WORKOS_CLIENT_ID=your_workos_client_id
WORKOS_API_KEY=your_workos_api_key
PAYLOAD_PUBLIC_SERVER_URL=https://your-domain.com
In your WorkOS dashboard:
1. Add a redirect URI: https://your-domain.com/workos-oauth/callback
2. Enable Google OAuth provider
3. Copy your Client ID and API Key
Only users with role: 'admin' can log in via OAuth. Make sure your users collection has this field configured.
These options are passed to the workosOAuthPlugin() function:
| Option | Type | Required | Description |
| ----------------- | -------- | -------- | ----------------------------------------------------------------------- |
| clientID | string | Yes | Your WorkOS Client ID |clientSecret
| | string | Yes | Your WorkOS API Key |callbackURL
| | string | Yes | The OAuth callback URL |authorizePath
| | string | No | Custom authorization endpoint path (default: "/workos-oauth/authorize") |callbackPath
| | string | No | Custom callback endpoint path (default: "/workos-oauth/callback") |successRedirect
| | string | No | Custom redirect after login (default: "/admin") |
The BeforeLogin component accepts these optional props:
| Prop | Type | Default | Description |
| --------------- | --------- | ------------------------- | ------------------------------------------------- |
| authorizePath | string | "/workos-oauth/authorize" | Path to the authorization endpoint |buttonLabel
| | string | "Sign in with Google" | Text to display on the button |showDivider
| | boolean | true | Whether to show the "OR" divider below the button |
You can customize the button by creating a wrapper component:
`typescript
// src/components/CustomOAuthButton.tsx
'use client'
import { BeforeLogin } from 'payload-workos-oauth'
export default function CustomOAuthButton() {
return (
showDivider={false}
/>
)
}
`
Then use it in your config:
`typescript`
admin: {
components: {
beforeLogin: ["@/components/CustomOAuthButton"],
},
}
If you want to show only the OAuth button and hide the default email/password login form, you can:
1. Set showDivider={false} on the BeforeLogin component
2. Use CSS to hide the default form
`typescript
// src/components/OAuthOnly.tsx
'use client'
import { BeforeLogin } from 'payload-workos-oauth'
export default function OAuthOnly() {
return (
<>
>
)
}
`
Then use it in your config:
`typescript`
admin: {
components: {
beforeLogin: ["@/components/OAuthOnly"],
},
}
You can create a completely custom button component from scratch:
`typescript
// src/components/MyCustomOAuthButton.tsx
'use client'
import React from 'react'
export default function MyCustomOAuthButton() {
const handleLogin = () => {
window.location.href = '/workos-oauth/authorize'
}
return (
)
}
`
Then add it to your Payload config:
`typescript`
admin: {
components: {
beforeLogin: ["@/components/MyCustomOAuthButton"],
},
}
1. User clicks "Sign in with Google" on the Payload admin login page
2. User is redirected to WorkOS/Google OAuth
3. User authenticates with Google
4. WorkOS redirects back to your callback URL with an authorization code
5. Plugin exchanges the code for user profile information
6. Plugin finds the user in Payload by email (must have role: 'admin')
7. Plugin generates a JWT token and sets a secure cookie
8. User is redirected to the admin dashboard
- Only users with role: 'admin' can authenticate via OAuthhttpOnly` flag for security
- JWT tokens are signed with your Payload secret
- Cookies are set with
- All server-side modules are properly isolated from client bundle
MIT
Bibek Thapa
Contributions are welcome! Please open an issue or submit a pull request.