Skip to main content

Elevating User Context via Platform Events for License-Constrained Operations

Portal and community users often need to trigger operations that require Salesforce licenses they do not hold. For example, a customer portal user may need to initiate a pricing calculation that requires a Revenue Cloud license, or a partner user may need to generate an order that invokes CPQ logic. Attempting these operations directly results in license errors or insufficient privileges exceptions.

The Problem

When a portal user executes Apex -- whether through a Lightning component, Flow, or API call -- the code runs in that user's context. If the operation requires entitlements tied to a specific license (e.g., Salesforce CPQ, Revenue Cloud, or Industries Cloud), the transaction fails because the portal user's license does not include those entitlements.

Granting full licenses to portal users is neither cost-effective nor architecturally sound.

The Solution: Platform Event Context Elevation

The pattern decouples the request (portal user context) from the execution (integration user context) using Platform Events.

Step 1: Define the Platform Event

Create a Platform Event that carries the data needed to perform the operation:

<!-- force-app/main/default/objects/Pricing_Request__e/Pricing_Request__e.object-meta.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<CustomObject xmlns="http://soap.sforce.com/2006/metadataAPI">
<label>Pricing Request</label>
<pluralLabel>Pricing Requests</pluralLabel>
<deploymentStatus>Deployed</deploymentStatus>
<eventType>HighVolume</eventType>
<fields>
<fullName>Quote_Id__c</fullName>
<label>Quote Id</label>
<type>Text</type>
<length>18</length>
</fields>
<fields>
<fullName>Requesting_User_Id__c</fullName>
<label>Requesting User Id</label>
<type>Text</type>
<length>18</length>
</fields>
</CustomObject>

Step 2: Publish from Portal Context

The portal user's action publishes the event. This requires no special license -- any user can publish Platform Events:

public class PricingRequestPublisher {

public static void requestPricing(Id quoteId) {
Pricing_Request__e event = new Pricing_Request__e(
Quote_Id__c = quoteId,
Requesting_User_Id__c = UserInfo.getUserId()
);

Database.SaveResult result = EventBus.publish(event);
if (!result.isSuccess()) {
throw new AuraHandledException('Failed to submit pricing request.');
}
}
}

Step 3: Configure the Subscriber to Run as an Elevated User

This is the critical piece. Use PlatformEventSubscriberConfig metadata to specify which user executes the subscriber trigger:

<!-- force-app/main/default/platformEventSubscriberConfigs/PricingRequestSubscriber.platformEventSubscriberConfig-meta.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<PlatformEventSubscriberConfig xmlns="http://soap.sforce.com/2006/metadataAPI">
<platformEventConsumer>PricingRequestTrigger</platformEventConsumer>
<masterLabel>Pricing Request Subscriber</masterLabel>
<batchSize>200</batchSize>
<user>integration-user@acmecorp.com</user>
<isProtected>false</isProtected>
</PlatformEventSubscriberConfig>

The user field references an integration user that holds the required license (e.g., Revenue Cloud). The subscriber trigger now runs with that user's full entitlements.

Step 4: Subscriber Trigger with Context Detection

The trigger executes the license-constrained logic. Optionally, detect the originating user type for audit or branching logic:

trigger PricingRequestTrigger on Pricing_Request__e (after insert) {
List<Id> quoteIds = new List<Id>();

for (Pricing_Request__e event : Trigger.New) {
quoteIds.add(event.Quote_Id__c);
}

// This code now runs as the integration user with full license entitlements
PricingService.calculatePricing(quoteIds);
}

Security Considerations

  • Principle of least privilege: The integration user should have only the permissions required for the specific operation, not a System Administrator profile.
  • Audit trail: Always capture the Requesting_User_Id__c so you can trace which portal user initiated the action.
  • Data validation: The subscriber trigger must validate all inputs from the event payload. Portal users control what gets published, so treat event data as untrusted input.
  • Error handling: Since the operation is asynchronous, implement a callback mechanism (e.g., update a status field on the record, send a Platform Event back) to notify the portal user of success or failure.
  • Governor limits: Platform Event triggers run in their own execution context with fresh governor limits, which is an additional benefit for heavy operations.

When to Use This Pattern

  • Portal or community users need to trigger CPQ pricing, Revenue Cloud billing, or other licensed operations
  • External integrations need to execute logic requiring specific Salesforce entitlements
  • You need to decouple a user-facing action from a heavyweight backend process while also elevating permissions

This pattern is not a workaround -- it is the Salesforce-recommended approach for running subscriber logic under a specific user context, introduced with the PlatformEventSubscriberConfig metadata type.