Overview
The Actions API enables you to implement custom business logic during critical authentication and user registration events. You can approve, deny, or modify these flows in real-time based on your application’s requirements.
Actions work through webhooks. WorkOS sends action requests to your endpoint, you process them, and return a signed response to approve or deny the action.
Methods
constructAction
Verifies and constructs an action context from an incoming webhook payload.
Options for constructing and verifying the action The raw webhook payload received from WorkOS
The WorkOS-Signature header from the webhook request
Your webhook secret for verifying the signature
Time tolerance in milliseconds for timestamp verification (default: 30000)
The verified action context Show Authentication Action
Unique identifier for the action
object
'authentication_action_context'
Object type identifier
The user attempting to authenticate
The organization the user is authenticating into (if applicable)
The user’s membership in the organization (if applicable)
IP address of the authentication attempt
User agent string from the authentication request
Show User Registration Action
Unique identifier for the action
object
'user_registration_action_context'
Object type identifier
Data about the user being registered
email - User’s email address
firstName - User’s first name
lastName - User’s last name
The invitation used for registration (if applicable)
IP address of the registration attempt
User agent string from the registration request
Example
import { WorkOS } from '@workos-inc/node' ;
import express from 'express' ;
const app = express ();
const workos = new WorkOS ( 'sk_example_123456789' );
app . post ( '/actions/authentication' , express . raw ({ type: 'application/json' }), async ( req , res ) => {
const signature = req . headers [ 'workos-signature' ] as string ;
const secret = 'wh_secret_123456789' ;
try {
const action = await workos . actions . constructAction ({
payload: JSON . parse ( req . body . toString ()),
sigHeader: signature ,
secret ,
tolerance: 30000 ,
});
// Process the action based on type
if ( action . object === 'authentication_action_context' ) {
console . log ( 'User attempting to sign in:' , action . user . email );
// Add your custom logic here
}
} catch ( error ) {
console . error ( 'Invalid action signature:' , error );
return res . status ( 400 ). send ( 'Invalid signature' );
}
});
signResponse
Creates a signed response to approve or deny an action.
data
AuthenticationActionResponseData | UserRegistrationActionResponseData
required
The response data to sign type
'authentication' | 'user_registration'
required
The type of action being responded to
Whether to allow or deny the action
Error message to display to the user if verdict is ‘Deny’
Your webhook secret for signing the response
The signed response object The response payload with timestamp and verdict
HMAC signature for verification
Example - Allow Authentication
const response = await workos . actions . signResponse (
{
type: 'authentication' ,
verdict: 'Allow' ,
},
'wh_secret_123456789' ,
);
res . json ( response );
Example - Deny Authentication
const response = await workos . actions . signResponse (
{
type: 'authentication' ,
verdict: 'Deny' ,
errorMessage: 'Your account has been suspended. Please contact support.' ,
},
'wh_secret_123456789' ,
);
res . json ( response );
Example - Conditional Logic
app . post ( '/actions/authentication' , express . raw ({ type: 'application/json' }), async ( req , res ) => {
const signature = req . headers [ 'workos-signature' ] as string ;
const secret = 'wh_secret_123456789' ;
const action = await workos . actions . constructAction ({
payload: JSON . parse ( req . body . toString ()),
sigHeader: signature ,
secret ,
});
// Example: Block authentication from specific IP ranges
const blockedIpRanges = [ '192.168.1.' , '10.0.0.' ];
const isBlockedIp = blockedIpRanges . some ( range =>
action . ipAddress ?. startsWith ( range )
);
const response = await workos . actions . signResponse (
{
type: 'authentication' ,
verdict: isBlockedIp ? 'Deny' : 'Allow' ,
errorMessage: isBlockedIp
? 'Authentication from this network is not permitted.'
: undefined ,
},
secret ,
);
res . json ( response );
});
Verifies the signature of an incoming webhook request. This method is available as a standalone utility.
Verification options The WorkOS-Signature header
Time tolerance in milliseconds (default: 30000)
Example
try {
await workos . actions . verifyHeader ({
payload: req . body ,
sigHeader: req . headers [ 'workos-signature' ] as string ,
secret: 'wh_secret_123456789' ,
tolerance: 30000 ,
});
console . log ( 'Signature verified' );
} catch ( error ) {
console . error ( 'Invalid signature' );
}
Use Cases
IP Allowlisting Restrict authentication to specific IP addresses or networks
Email Domain Validation Ensure users register with approved email domains
Account Suspension Prevent suspended users from authenticating
Custom Onboarding Add users to external systems during registration
Fraud Prevention Block suspicious registration patterns or device fingerprints
Conditional Access Implement time-based or location-based access controls
Best Practices
Always verify webhook signatures using constructAction or verifyHeader before processing action requests.
Actions must respond within 3 seconds . Implement async processing for time-consuming operations and return a cached or default response immediately.
When denying an action, provide clear errorMessage text to help users understand why their request was denied and what they can do to resolve it.
Webhooks Configure webhook endpoints for Actions
User Management Manage users and authentication