payload-auth-cookie
v0.0.14
Published
Payload CMS authentication plugin for Cookies from external SSO
Downloads
298
Maintainers
Readme
payload-auth-cookie
A Payload CMS authentication plugin for external SSO cookie-based authentication.
This plugin allows you to authenticate users based on cookies set by an external SSO system. It validates sessions via a configurable session endpoint and maps users to Payload CMS collections.
Features
- 🍪 Cookie-based authentication from external SSO systems
- 🔑 JWT verification with configurable secret (no external API call needed)
- 🔐 Support for both admin panel and frontend authentication
- 👤 Automatic user creation with configurable sign-up policy
- 🔄 Session validation via external API or JWT verification
- 📦 TypeScript support with full type definitions
Installation
npm install payload-auth-cookie
# or
pnpm add payload-auth-cookie
# or
yarn add payload-auth-cookieQuick Start
1. Configure the Plugin
// payload.config.ts
import { buildConfig } from 'payload'
import { authPlugin } from 'payload-auth-cookie'
export default buildConfig({
plugins: [
authPlugin({
name: 'admin',
useAdmin: true,
usersCollectionSlug: 'adminUsers',
successRedirectPath: '/admin',
sso: {
cookieName: process.env.SSO_COOKIE_NAME!,
loginUrl: process.env.SSO_LOGIN_URL!,
logoutUrl: process.env.SSO_LOGOUT_URL!,
sessionUrl: process.env.SSO_SESSION_URL!,
},
}),
],
})2. Create a Users Collection
// collections/Users.ts
import { withUsersCollection } from 'payload-auth-cookie/collection'
export const AdminUsers = withUsersCollection({
slug: 'adminUsers',
auth: {
disableLocalStrategy: true,
},
fields: [
{
name: 'name',
type: 'text',
},
],
})3. Add Login Button to Admin Panel
// components/SSOLoginButton.tsx
'use client'
import { LoginButton } from 'payload-auth-cookie/client'
export default function SSOLoginButton() {
return <LoginButton href="/api/admin/auth/login" label="Sign in with SSO" />
}// payload.config.ts
export default buildConfig({
admin: {
components: {
afterLogin: ['@/components/SSOLoginButton'],
},
},
// ...
})Configuration
Plugin Options
| Option | Type | Required | Default | Description |
|--------|------|----------|---------|-------------|
| name | string | ✅ | - | Unique name for this auth configuration (used in endpoint paths) |
| usersCollectionSlug | string | ✅ | - | Slug of the users collection to authenticate against |
| sso | SSOProviderConfig | ✅ | - | SSO provider configuration |
| useAdmin | boolean | ❌ | false | Use this configuration for admin panel authentication |
| allowSignUp | boolean | ❌ | false | Allow creating new users on first login |
| successRedirectPath | string | ❌ | '/' | Path to redirect after successful authentication |
| errorRedirectPath | string | ❌ | '/auth/error' | Path to redirect on authentication error |
| onSuccess | function | ❌ | - | Callback after successful authentication |
| onError | function | ❌ | - | Callback on authentication error |
SSO Provider Configuration
| Option | Type | Required | Default | Description |
|--------|------|----------|---------|-------------|
| cookieName | string | ✅ | - | Name of the cookie set by your SSO system |
| loginUrl | string | ✅ | - | URL to redirect for SSO login |
| logoutUrl | string | ✅ | - | URL to redirect for SSO logout |
| sessionUrl | string | ⚠️ | - | URL to validate session (required if jwt not provided) |
| jwt | JWTVerificationConfig | ⚠️ | - | JWT verification config (required if sessionUrl not provided) |
| timeoutMs | number | ❌ | 5000 | Timeout for session validation requests |
JWT Verification Configuration
When your SSO cookie contains a JWT, you can verify it locally without calling an external session endpoint:
| Option | Type | Required | Default | Description |
|--------|------|----------|---------|-------------|
| secret | string | ✅ | - | Secret key for verifying JWT signatures |
| algorithm | string | ❌ | 'HS256' | JWT algorithm (HS256, HS384, HS512) |
| issuer | string | ❌ | - | Expected issuer (iss claim) |
| audience | string | ❌ | - | Expected audience (aud claim) |
| emailField | string | ❌ | 'email' | Field path to extract email (supports dot notation) |
| firstNameField | string | ❌ | 'firstName' | Field path to extract first name |
| lastNameField | string | ❌ | 'lastName' | Field path to extract last name |
| profilePictureUrlField | string | ❌ | 'profilePictureUrl' | Field path to extract profile picture URL |
Field Mappings
Map SSO response fields to your collection's field names:
| Option | Type | Required | Default | Description |
|--------|------|----------|---------|-------------|
| fieldMappings.nameField | string | ❌ | 'name' | SSO field containing the user's full name |
| fieldMappings.firstNameField | string | ❌ | 'firstName' | SSO field containing the user's first name |
| fieldMappings.lastNameField | string | ❌ | 'lastName' | SSO field containing the user's last name |
| fieldMappings.profilePictureUrlField | string | ❌ | 'profilePictureUrl' | SSO field containing the profile picture URL |
| fieldMappings.emailVerifiedField | string | ❌ | 'emailVerified' | SSO field indicating email verification status |
| fieldMappings.lastLoginAtField | string | ❌ | 'lastLoginAt' | SSO field containing last login timestamp |
Field Mappings Example
authPlugin({
name: 'app',
usersCollectionSlug: 'appUsers',
sso: {
cookieName: 'sso_token',
loginUrl: 'https://sso.example.com/login',
logoutUrl: 'https://sso.example.com/logout',
jwt: {
secret: process.env.SSO_JWT_SECRET!,
},
fieldMappings: {
nameField: 'full_name', // Maps SSO's full_name → user.name
profilePictureUrlField: 'avatar', // Maps SSO's avatar → user.profilePictureUrl
},
},
})JWT Configuration Example
authPlugin({
name: 'admin',
useAdmin: true,
usersCollectionSlug: 'adminUsers',
sso: {
cookieName: 'sso_token',
loginUrl: 'https://sso.example.com/login',
logoutUrl: 'https://sso.example.com/logout',
jwt: {
secret: process.env.SSO_JWT_SECRET!,
algorithm: 'HS256',
issuer: 'https://sso.example.com',
emailField: 'user.email', // For nested JWT payloads
},
},
})Authentication Flow
Admin Login Flow
- User navigates to
/admin - If not authenticated, clicks "Sign in with SSO" button
- Plugin redirects to
loginUrlwithreturnUrlparameter - User authenticates with external SSO
- SSO system sets a cookie (e.g.,
supaku_session) - User is redirected back to
/api/admin/auth/login - Plugin validates cookie via
sessionUrlor JWT verification - Plugin finds/creates user and sets Payload session cookie
- User is redirected to
/admin
Frontend Login Flow
- User navigates to
/auth/login(or custom login page) - App redirects to
/api/app/auth/login - If no SSO cookie, redirects to
loginUrl - After SSO authentication, user returns with cookie
- Plugin validates and creates session
- User is redirected to success path
Session Validation Methods
Method 1: Session URL (API-based)
Your SSO session endpoint (sessionUrl) should:
- Accept the SSO cookie in the request
- Return JSON with at least an
emailfield - Return 200 OK for valid sessions
- Return non-2xx for invalid/expired sessions
Expected Response Format
The plugin supports multiple response formats:
Direct user data:
{
"email": "[email protected]",
"firstName": "John",
"lastName": "Doe",
"profilePictureUrl": "https://example.com/avatar.jpg"
}Nested user object (automatically extracted):
{
"authenticated": true,
"user": {
"email": "[email protected]",
"firstName": "John",
"lastName": "Doe",
"profilePictureUrl": "https://example.com/avatar.jpg"
}
}Method 2: JWT Verification (Local)
If your SSO cookie is a JWT, configure jwt instead of sessionUrl:
sso: {
cookieName: 'sso_token',
loginUrl: 'https://sso.example.com/login',
logoutUrl: 'https://sso.example.com/logout',
jwt: {
secret: process.env.SSO_JWT_SECRET!,
},
}The JWT payload should contain at least an email field (configurable via emailField).
Multiple Auth Instances
You can configure multiple auth instances for different user types. Each instance creates its own set of endpoints and correctly returns users from its associated collection:
plugins: [
authPlugin({
name: 'admin',
useAdmin: true,
usersCollectionSlug: 'adminUsers',
successRedirectPath: '/admin',
sso: adminSSOConfig,
}),
authPlugin({
name: 'app',
allowSignUp: true,
usersCollectionSlug: 'appUsers',
successRedirectPath: '/',
sso: appSSOConfig,
}),
]With this configuration:
/api/admin/auth/sessionreturns users fromadminUserscollection/api/app/auth/sessionreturns users fromappUserscollection- Each endpoint syncs SSO data to its own collection's user records
- Authentication strategies are uniquely named (
sso-cookie-adminUsers,sso-cookie-appUsers)
API Endpoints
The plugin creates the following endpoints (prefixed with your configured name):
| Endpoint | Method | Description |
|----------|--------|-------------|
| /api/{name}/auth/login | GET | Initiates login or validates SSO cookie |
| /api/{name}/auth/logout | GET | Clears session and redirects to SSO logout |
| /api/{name}/auth/session | GET | Returns current session status |
| /api/users/me | GET | Returns current user (for Payload admin bar compatibility) |
Admin Bar Compatibility
The plugin automatically adds a /api/users/me endpoint to support the Payload admin bar, which expects this endpoint to exist. This works around an issue where Payload calls /api/users/me on every page load even when disableLocalStrategy: true is set on the users collection.
Helper Functions
Server-Side
import {
validateSSOSession,
verifyJWTSession,
fetchSSOSession,
getEmailFromSession,
parseCookies,
generateUserToken,
} from 'payload-auth-cookie'Client-Side
import { LoginButton, AuthProvider, useAuth } from 'payload-auth-cookie/client'Environment Variables
# Common
SSO_COOKIE_NAME=supaku_session
SSO_LOGIN_URL=https://sso.example.com/login
SSO_LOGOUT_URL=https://sso.example.com/logout
# For Session URL validation
SSO_SESSION_URL=https://sso.example.com/api/session
# For JWT verification (alternative to SESSION_URL)
SSO_JWT_SECRET=your-jwt-signing-secretLicense
MIT
