Safely Apply Content Filtering

The best way to ensure that your indexed content is seen only by the intended users is to enforce content security when configuring your Salesforce source. The Users Following System Permissions source configuration option replicates the security model of your Salesforce organization, which means that users only see the content that they’re allowed to see in Salesforce when obtaining search results from a Coveo index.

However, you may face situations where you have to configure your source to be accessible to Everyone. This is typically the case when you index Salesforce Knowledge Base (KB) records that are based on data categories as Coveo can’t replicate this security model (see Limitations).

Tip
Leading practice

When using the Salesforce Sharing for Lightning Knowledge security model, Coveo automatically supports permissions set on Online, Draft, and Archived articles.

This article provides the leading practices to safely filter content from a source whose content is accessible to Everyone in a Salesforce Community.

Configure Query Filters

Filter rules allow you to enter hidden query expressions to be added to all queries going through a given query pipeline. They’re typically used to add a field-based expression to the constant query expression (cq).

Example

You apply the @objectType=="Solution" query filter to the pipeline to which the traffic of your public support portal is directed. As a result, the @objectType=="Solution" query expression is added to any query sent via this support portal.

Therefore, if a user types Speedbit watch wristband in the searchbox, the items returned are those that match these keywords and whose objectType has the Solution value. Items matching these keywords but having a different objectType value aren’t returned in the user’s search results.

Important

Filters, by themselves, don’t prevent the exposure of filtered content. We therefore strongly advise against creating a source whose content is accessible to everyone and using a pipeline filter to exclude sensitive information.

In the following cases, sensitive content from a source whose content is accessible to everyone could be exposed:

  • A filter rule based on the aq query parameter is set on a query pipeline that contains an ART model for which the Match the advanced query option is disabled.

  • Using other pipelines not having a similar filter from other search interfaces or directly from the API.

  • A colleague not understanding the reason for the filter could modify or remove the filter.

To learn how to configure query pipeline filter rules, see Manage Filter Rules.

Note

You can enforce a filter expression directly in the search token. See Configure the Search Token for instructions.

Use the Proper Query Pipeline Routing Mechanism

The most recommended and flexible query pipeline routing mechanism is condition-based routing.

In this scenario, search requests are authenticated with a search token that contains a searchHub parameter, and each query pipeline except the default one has a distinct query pipeline condition based on a specific search hub value such as Search Hub is Community Search or Search Hub is Agent Panel. When using this routing mechanism, you ensure that search requests are routed according to the search interface from which they originate.

Important

You should always use positive operators (e.g., is, contains, or matches) when creating a condition that aims at routing the queries originating from a specific search interface to a given query pipeline.

Configure the Search Token

When using query filters to secure content, the safest way to enforce content security is to authenticate user queries using a search token that’s generated server side.

For instance, when using this approach, you can enforce a search hub value in the search token, which will make every authenticated request originating from the desired component use the specified search hub. Because this configuration is stored server side and encrypted in the search token, it can’t be modified by users or client-side code.

The procedure to generate a custom search token differs depending on the origin of the authenticated request:

Configure the Search Token for a Community Search Component

Since the Coveo for Salesforce (v4.23) release, you can enforce a search hub in the search token that authenticates queries originating from a Coveo Lightning Community Search component by using the Search Hub option in the Advanced Server-Side Configuration panel.

Note

Setting a search hub using the Search Hub option of the Advanced Server-Side Configuration will override any search hub value set when building the page.

Doing so prevents you from having to create an Apex Class to generate a custom search token.

If you choose this approach to enforce a search hub in your search token, you can skip to step 5.

Step 1: Create an Apex Class to Generate the Search Token

  1. In Salesforce, access the Developer Console.

  2. In the Developer Console, create a new Apex class ( File > New > Apex Class).

  3. In the new Apex class, enter the following template:

     public with sharing class <MY_APEX_CLASS> {
         // Annotate the method so that it's accessible from the Lightning component
         @AuraEnabled
         public static string getToken() {
             // Generate a token using the Globals class provided by Coveo.
             // See the Globals Class documentation: https://docs.coveo.com/en/1075/coveo-for-salesforce/globals-class
             Map<String, Object> endpoint = CoveoV2.Globals.getEndpointData();
             endpoint.put('token', CoveoV2.Globals.generateSearchToken());
             return JSON.serialize(endpoint);
         }
     }

    Where you replace <MY_APEX_CLASS> with the name you chose for your Apex class.

  4. In the getToken() class, enter your code to create the custom search token. Modify that code to at least include the searchHub in your token generation steps.

    Warning

    For content security reasons, don’t specify a search hub value as a parameter of the getToken() class (e.g., getToken(String searchHub).

    Example
    public with sharing class <MY_APEX_CLASS> {
        // Annotate the method so that it's accessible from the Lightning component
         @AuraEnabled
         public static string getToken() {
             // Generate a token using the Globals class provided by Coveo.
             // See the Globals Class documentation: https://docs.coveo.com/en/1075/coveo-for-salesforce/globals-class
            Map<String, Object> endpoint = CoveoV2.Globals.getEndpointData();
            endpoint.put('token', CoveoV2.Globals.generateSearchToken(new Map<String, Object> {
             'searchHub' => '<MY_SEARCH_HUB>'
             }));
            return JSON.serialize(endpoint);
        }
    }

    Where you replace <MY_SEARCH_HUB> with the name of the search hub to enforce in the search token.

    Note that you can specify other parameters in the search token, such as query filters or a query pipeline.

    See Globals Class for instructions.

  5. Save the Apex class.

Note

While you can use the Advanced Server-Side Configuration panel to add configurations to the search token, this panel doesn’t let you enforce a specific query pipeline in the search token.

Step 2: Create the Custom Lightning Endpoint Handler

Now that you have created your Apex class, you must create a custom Lightning endpoint handler to reference your Apex class in your Lightning component.

  1. In the Developer Console, create a Lightning component.

  2. In the component .cmp, add the following code:

    <aura:component controller="<MY_APEX_CLASS>" >
        <!-- GET THE ENDPOINT INITIALIZATION DATA -->
        <aura:method name="getEndpoint" action="{!c.getTokenAction}" access="global">
            <aura:attribute name="name" type="String" />
        </aura:method>
        <!-- RENEW THE ENDPOINT ACCESS TOKEN -->
        <aura:method name="renewAccessToken" action="{!c.getTokenAction}" access="global">
            <aura:attribute name="name" type="String" />
        </aura:method>
    </aura:component>

    Where you replace <MY_APEX_CLASS> with the name of the Apex class you created in previous step.

  3. In the controller.js file, enter the following code:

    ({
        getTokenAction: function(component, event, helper) {
            const getTokenAction = component.get('c.getToken');
            var getTokenPromise = new Promise(function (resolve, reject) {
                getTokenAction.setCallback(this, function (response) {
                    if (response.getState() === 'SUCCESS') {
                        var responseData = response.getReturnValue();
                        resolve(JSON.parse(responseData));
                    } else if (response.getState() === 'ERROR') {
                        reject(Error('Error generating token'));
                    }
                });
            });
    
            $A.enqueueAction(getTokenAction);
            return getTokenPromise;
        }
    });
  4. Save the file.

Your custom Lightning endpoint handler is now ready.

Note

In our simple example, since there’s no difference between the generation and the renewal of a token, we call the same controller.js method twice.

Step 3: Reference the Custom Lightning Endpoint Handler in a Community Search Component

Now that you have created your Apex class to generate a custom search token and a custom Lightning endpoint handler, you must reference the custom Lightning endpoint handler in a Community Search component.

Note

The following procedure assumes that you have wrapped a default Coveo Lightning component to create a custom Lightning component. See Integrating Coveo Components in a Custom Lightning Component for Your Community for instructions.

  1. In Salesforce, access an existing custom Lightning component, or create a new one.

  2. In the component .cmp, ensure that your component references the custom Lightning endpoint handler you created in the last step. For example, the component .cmp should look like the following:

    <aura:component implements='forceCommunity:availableForAllPageTypes'>
        <aura:attribute name="endpointHandler" type="Aura.Component[]" access="global">
            <c:<MY_CUSTOM_ENDPOINT_HANDLER>></c:<MY_CUSTOM_ENDPOINT_HANDLER>>
        </aura:attribute>
        <CoveoV2:CommunitySearch endpointHandler="{!v.endpointHandler}"/>
    </aura:component>

    Where you replace <MY_CUSTOM_ENDPOINT_HANDLER> with the name of the custom endpoint handler you created in the last step.

  3. Save the Lightning component.

Step 4: Ensure Your Community Search Component Generates the Search Token Server Side

Now that your custom Community Search component references your custom code to generate a search token, make sure that your component uses your code to generate the search token server side.

  1. In the Lightning Community where your custom Lightning component is integrated, access the Preview mode.

  2. Access the Advanced Server-Side Configuration panel for the component that must use the custom search token:

    With Coveo for Salesforce v3.25+ With Coveo for Salesforce V3

    At the upper-right corner of the component, click the cogwheel icon, and then select Advanced Configuration.

    At the upper-left corner of the component, click the cogwheel icon, and then select Advanced Lightning Configuration.

  3. In the Advanced Server-Side Configuration panel that opens, click the Bypass above settings to rather generate the search token from a custom Apex class check box to use your Apex class to generate the search token for this component.

Step 5: Validate the Search Token

Now that you’re enforcing configurations in a search token that’s generated server side, you should validate that the search token enforces the proper parameters to ensure that your content filtering is secure.

Configure the Search Token for a Community Search Box Component

The Community Search Box component inherits its search token configuration from the Community Search component if they share the same name.

Therefore, if you specified a search hub value in the Search Hub option of the Advanced Server-Side Configuration panel of the Community Search component, you don’t need to create an Apex Class to generate a custom search token, and you can skip to step 5.

Step 1: Create an Apex Class to Generate the Search Token

  1. In Salesforce, access the Developer Console.

  2. In the Developer Console, create a new Apex class ( File > New > Apex Class).

  3. In the new Apex class, enter the following template:

     public with sharing class <MY_APEX_CLASS> {
         // Annotate the method so that it's accessible from the Lightning component
         @AuraEnabled
         public static string getToken() {
             // Generate a token using the Globals class provided by Coveo.
             // See the Globals Class documentation: https://docs.coveo.com/en/1075/coveo-for-salesforce/globals-class
             Map<String, Object> endpoint = CoveoV2.Globals.getEndpointData();
             endpoint.put('token', CoveoV2.Globals.generateSearchToken());
             return JSON.serialize(endpoint);
         }
     }

    Where you replace <MY_APEX_CLASS> with the name you chose for your Apex class.

  4. In the getToken() class, enter your code to create the custom search token. Modify that code to at least include the searchHub in your token generation steps.

    Warning

    For content security reasons, don’t specify a search hub value as a parameter of the getToken() class (e.g., getToken(String searchHub).

    Example
    public with sharing class <MY_APEX_CLASS> {
        // Annotate the method so that it's accessible from the Lightning component
         @AuraEnabled
         public static string getToken() {
             // Generate a token using the Globals class provided by Coveo.
             // See the Globals Class documentation: https://docs.coveo.com/en/1075/coveo-for-salesforce/globals-class
            Map<String, Object> endpoint = CoveoV2.Globals.getEndpointData();
            endpoint.put('token', CoveoV2.Globals.generateSearchToken(new Map<String, Object> {
             'searchHub' => '<MY_SEARCH_HUB>'
             }));
            return JSON.serialize(endpoint);
        }
    }

    Where you replace <MY_SEARCH_HUB> with the name of the search hub to enforce in the search token.

    Note that you can specify other parameters in the search token, such as query filters or a query pipeline.

    See Globals Class for instructions.

  5. Save the Apex class.

Step 2: Create the Custom Lightning Endpoint Handler

Now that you have created your Apex class, you must create a custom Lightning endpoint handler to reference your Apex class in your Lightning component.

  1. In the Developer Console, create a Lightning component.

  2. In the component .cmp, add the following code:

    <aura:component controller="<MY_APEX_CLASS>" >
        <!-- GET THE ENDPOINT INITIALIZATION DATA -->
        <aura:method name="getEndpoint" action="{!c.getTokenAction}" access="global">
            <aura:attribute name="name" type="String" />
        </aura:method>
        <!-- RENEW THE ENDPOINT ACCESS TOKEN -->
        <aura:method name="renewAccessToken" action="{!c.getTokenAction}" access="global">
            <aura:attribute name="name" type="String" />
        </aura:method>
    </aura:component>

    Where you replace <MY_APEX_CLASS> with the name of the Apex class you created in previous step.

  3. In the controller.js file, enter the following code:

    ({
        getTokenAction: function(component, event, helper) {
            const getTokenAction = component.get('c.getToken');
            var getTokenPromise = new Promise(function (resolve, reject) {
                getTokenAction.setCallback(this, function (response) {
                    if (response.getState() === 'SUCCESS') {
                        var responseData = response.getReturnValue();
                        resolve(JSON.parse(responseData));
                    } else if (response.getState() === 'ERROR') {
                        reject(Error('Error generating token'));
                    }
                });
            });
    
            $A.enqueueAction(getTokenAction);
            return getTokenPromise;
        }
    });
  4. Save the file.

Your custom Lightning endpoint handler is now ready.

Note

In our simple example, since there’s no difference between the generation and the renewal of a token, we call the same controller.js method twice.

Step 3: Reference the Custom Lightning Endpoint Handler in a Community Search Box Component

Now that you have created your Apex class to generate a custom search token and a custom Lightning endpoint handler, you must reference the custom Lightning endpoint handler in a Community Search Box component.

Note

The following procedure assumes that you have wrapped a default Coveo Lightning component to create a custom Lightning component. See Integrating Coveo Components in a Custom Lightning Component for Your Community for instructions.

  1. In Salesforce, access an existing custom Lightning component, or create a new one.

  2. In the component .cmp, ensure that your component references the custom Lightning endpoint handler you created in the last step. For example, the component .cmp should look like the following:

    <aura:component implements='forceCommunity:searchInterface'>
        <aura:attribute name="endpointHandler" type="Aura.Component[]" access="global">
            <c:<MY_CUSTOM_ENDPOINT_HANDLER>></c:<MY_CUSTOM_ENDPOINT_HANDLER>>
        </aura:attribute>
        <CoveoV2:CommunitySearchBox endpointHandler="{!v.endpointHandler}"/>
    </aura:component>

    Where you replace <MY_CUSTOM_ENDPOINT_HANDLER> with the name of the custom endpoint handler you created in the last step.

  3. Save the Lightning component.

Step 4: Ensure Your Community Search Box Component Generates the Search Token Server Side

The Community Search Box component inherits its configuration from the Community Search component if they share the same name.

Therefore, any change made to the Advanced Server-Side Configuration panel, such as activating the Bypass above settings to rather generate the search token from a custom Apex class option will be replicated in your Community Search Box component’s configuration.

Step 5: Validate the Search Token

Now that you’re enforcing configurations in a search token that’s generated server side, you should validate that the search token enforces the proper parameters to ensure that your content filtering is secure.

To do so, you should inspect the search token that appears in the request headers of a POST request made against a Coveo query suggest endpoint (e.g., search/v2/querySuggest).

Configure the Search Token for a Case Deflection Component

Since the Coveo for Salesforce (v4.23) release, you can enforce a search hub in the search token that authenticates queries originating from a Coveo Lightning Case Deflection component by using the Search Hub option in the Advanced Server-Side Configuration panel.

Note

Setting a search hub using the Search Hub option of the Advanced Server-Side Configuration will override any search hub value set when building the page.

Doing so prevents you from having to create an Apex Class to generate a custom search token.

If you choose this approach to enforce a search hub in your search token, you can skip to step 5.

Step 1: Create an Apex Class to Generate the Search Token

  1. In Salesforce, access the Developer Console.

  2. In the Developer Console, create a new Apex class ( File > New > Apex Class).

  3. In the new Apex class, enter the following template:

     public with sharing class <MY_APEX_CLASS> {
         // Annotate the method so that it's accessible from the Lightning component
         @AuraEnabled
         public static string getToken() {
             // Generate a token using the Globals class provided by Coveo.
             // See the Globals Class documentation: https://docs.coveo.com/en/1075/coveo-for-salesforce/globals-class
             Map<String, Object> endpoint = CoveoV2.Globals.getEndpointData();
             endpoint.put('token', CoveoV2.Globals.generateSearchToken());
             return JSON.serialize(endpoint);
         }
     }

    Where you replace <MY_APEX_CLASS> with the name you chose for your Apex class.

  4. In the getToken() class, enter your code to create the custom search token. Modify that code to at least include the searchHub in your token generation steps.

    Warning

    For content security reasons, don’t specify a search hub value as a parameter of the getToken() class (e.g., getToken(String searchHub).

    Example
    public with sharing class <MY_APEX_CLASS> {
        // Annotate the method so that it's accessible from the Lightning component
         @AuraEnabled
         public static string getToken() {
             // Generate a token using the Globals class provided by Coveo.
             // See the Globals Class documentation: https://docs.coveo.com/en/1075/coveo-for-salesforce/globals-class
            Map<String, Object> endpoint = CoveoV2.Globals.getEndpointData();
            endpoint.put('token', CoveoV2.Globals.generateSearchToken(new Map<String, Object> {
             'searchHub' => '<MY_SEARCH_HUB>'
             }));
            return JSON.serialize(endpoint);
        }
    }

    Where you replace <MY_SEARCH_HUB> with the name of the search hub to enforce in the search token.

    Note that you can specify other parameters in the search token, such as query filters or a query pipeline.

    See Globals Class for instructions.

  5. Save the Apex class.

Note

While you can use the Advanced Server-Side Configuration panel to add configurations to the search token, this panel doesn’t let you enforce a specific query pipeline in the search token.

Step 2: Create the Custom Lightning Endpoint Handler

Now that you have created your Apex class, you must create a custom Lightning endpoint handler to reference your Apex class in your Lightning component.

  1. In the Developer Console, create a Lightning component.

  2. In the component .cmp, add the following code:

    <aura:component controller="<MY_APEX_CLASS>" >
        <!-- GET THE ENDPOINT INITIALIZATION DATA -->
        <aura:method name="getEndpoint" action="{!c.getTokenAction}" access="global">
            <aura:attribute name="name" type="String" />
        </aura:method>
        <!-- RENEW THE ENDPOINT ACCESS TOKEN -->
        <aura:method name="renewAccessToken" action="{!c.getTokenAction}" access="global">
            <aura:attribute name="name" type="String" />
        </aura:method>
    </aura:component>

    Where you replace <MY_APEX_CLASS> with the name of the Apex class you created in previous step.

  3. In the controller.js file, enter the following code:

    ({
        getTokenAction: function(component, event, helper) {
            const getTokenAction = component.get('c.getToken');
            var getTokenPromise = new Promise(function (resolve, reject) {
                getTokenAction.setCallback(this, function (response) {
                    if (response.getState() === 'SUCCESS') {
                        var responseData = response.getReturnValue();
                        resolve(JSON.parse(responseData));
                    } else if (response.getState() === 'ERROR') {
                        reject(Error('Error generating token'));
                    }
                });
            });
    
            $A.enqueueAction(getTokenAction);
            return getTokenPromise;
        }
    });
  4. Save the file.

Your custom Lightning endpoint handler is now ready.

Note

In our simple example, since there’s no difference between the generation and the renewal of a token, we call the same controller.js method twice.

Step 3: Reference the Custom Lightning Endpoint Handler in a Case Deflection Component

Now that you have created your Apex class to generate a custom search token and a custom Lightning endpoint handler, you must reference the custom Lightning endpoint handler in a Case Deflection component.

Note

The following procedure assumes that you have wrapped a default Coveo Lightning component to create a custom Lightning component. See Integrating Coveo Components in a Custom Lightning Component for Your Community for instructions.

  1. In Salesforce, access an existing custom Lightning component, or create a new one.

  2. In the component .cmp, ensure that your component references the custom Lightning endpoint handler you created in the last step. For example, the component .cmp should look like the following:

    <aura:component implements='forceCommunity:availableForAllPageTypes'>
        <aura:attribute name="endpointHandler" type="Aura.Component[]" access="global">
            <c:<MY_CUSTOM_ENDPOINT_HANDLER>></c:<MY_CUSTOM_ENDPOINT_HANDLER>>
        </aura:attribute>
        <CoveoV2:CaseDeflection endpointHandler="{!v.endpointHandler}"/>
    </aura:component>

    Where you replace <MY_CUSTOM_ENDPOINT_HANDLER> with the name of the custom endpoint handler you created in the last step.

  3. Save the Lightning component.

Step 4: Ensure Your Case Deflection Component Generates the Search Token Server Side

Now that your custom Case Deflection component references your custom code to generate a search token, make sure that your component uses your code to generate the search token server side.

  1. In the Lightning Community where your custom Lightning component is integrated, access the Preview mode.

  2. Access the Advanced Server-Side Configuration panel for the component that must use the custom search token:

    With Coveo for Salesforce v3.25+ With Coveo for Salesforce V3

    At the upper-right corner of the component, click the cogwheel icon, and then select Advanced Configuration.

    At the upper-left corner of the component, click the cogwheel icon, and then select Advanced Lightning Configuration.

  3. In the Advanced Server-Side Configuration panel that opens, click the Bypass above settings to rather generate the search token from a custom Apex class check box to use your Apex class to generate the search token for this component.

Step 5: Validate the Search Token

Now that you’re enforcing configurations in a search token that’s generated server side, you should validate that the search token enforces the proper parameters to ensure that your content filtering is secure.

Configure the Search Token for a Page View Tracker Component

The Page View Tracker component inherits its search token configuration from the Community Search component if they share the same name.

Therefore, if you specified a search hub value in the Search Hub option of the Advanced Server-Side Configuration panel of the Community Search component, you don’t need to create an Apex Class to generate a custom search token, and you can skip to step 4.

Step 1: Create an Apex Class to Generate the Search Token

  1. In Salesforce, access the Developer Console.

  2. In the Developer Console, create a new Apex class ( File > New > Apex Class).

  3. In the new Apex class, enter the following template:

     public with sharing class <MY_APEX_CLASS> {
         // Annotate the method so that it's accessible from the Lightning component
         @AuraEnabled
         public static string getToken() {
             // Generate a token using the Globals class provided by Coveo.
             // See the Globals Class documentation: https://docs.coveo.com/en/1075/coveo-for-salesforce/globals-class
             Map<String, Object> endpoint = CoveoV2.Globals.getEndpointData();
             endpoint.put('token', CoveoV2.Globals.generateSearchToken());
             return JSON.serialize(endpoint);
         }
     }

    Where you replace <MY_APEX_CLASS> with the name you chose for your Apex class.

  4. In the getToken() class, enter your code to create the custom search token. Modify that code to at least include the searchHub in your token generation steps.

    Warning

    For content security reasons, don’t specify a search hub value as a parameter of the getToken() class (e.g., getToken(String searchHub).

    Example
    public with sharing class <MY_APEX_CLASS> {
        // Annotate the method so that it's accessible from the Lightning component
         @AuraEnabled
         public static string getToken() {
             // Generate a token using the Globals class provided by Coveo.
             // See the Globals Class documentation: https://docs.coveo.com/en/1075/coveo-for-salesforce/globals-class
            Map<String, Object> endpoint = CoveoV2.Globals.getEndpointData();
            endpoint.put('token', CoveoV2.Globals.generateSearchToken(new Map<String, Object> {
             'searchHub' => '<MY_SEARCH_HUB>'
             }));
            return JSON.serialize(endpoint);
        }
    }

    Where you replace <MY_SEARCH_HUB> with the name of the search hub to enforce in the search token.

    Note that you can specify other parameters in the search token, such as query filters or a query pipeline.

    See Globals Class for instructions.

  5. Save the Apex class.

Step 2: Configure the Component to Reference the Apex Class

Now that you have created your Apex class, you must configure the Page View Tracker component to reference your Apex class.

Note

The following procedure assumes that you have wrapped a default Coveo Lightning component to create a custom Lightning component. See Integrating Coveo Components in a Custom Lightning Component for Your Community for instructions.

  1. In Salesforce, access an existing custom Page View Tracking Lightning component, or create a new one.

  2. In the component .cmp, ensure that your component references the Apex class you created in the last step. For example, the component .cmp should look like the following:

    <aura:component implements="forceCommunity:availableForAllPageTypes,force:hasRecordId,force:hasSObjectName" access="global" controller="<MY_APEX_CLASS>">
        <CoveoV2:PageViewTracker GetSearchToken="{!c.generateSearchToken}"
                                 contentIdValue="{!v.recordId}"
                                 name="{!v.name}" />
    </aura:component>

    Where you replace <MY_APEX_CLASS> with the name you chose for your Apex class in previous step.

  3. In the controller.js file, enter the following code:

    ({
        generateSearchToken: function(component, event, helper) {
            var deferred = event.getParam('deferred');
            var action = component.get('c.getToken');
            action.setCallback(this, function(response) {
                if (response.getState() == 'SUCCESS') {
                    deferred.resolve({
                        searchToken: response.getReturnValue()
                    })
                }
            });
            $A.enqueueAction(action);
        }
    })
  4. Save the component.

Your custom Page View Tracker component is now ready.

Step 3: Ensure Your Page View Tracker Component Generates the Search Token Server Side

The Page View Tracker component inherits its configuration from the Community Search component if they share the same name.

Therefore, any change made to the Advanced Server-Side Configuration panel, such as activating the Bypass above settings to rather generate the search token from a custom Apex class option will be replicated in your Page View Tracker component’s configuration.

Step 4: Validate the Search Token

Now that you’re enforcing configurations in a search token that’s generated server side, you should validate that the search token enforces the proper parameters to ensure that your content filtering is secure.

To do so, you should inspect the search token that appears in the request headers of a POST request made against the Coveo Usage Analytics Write API (e.g., /rest/ua/v15/analytics/).

Configure the Search Token for a Recommendations Component

The Recommendations component inherits its search token configuration from the Community Search component if they share the same name.

Therefore, if you specified a search hub value in the Search Hub option of the Advanced Server-Side Configuration panel of the Community Search component, you don’t need to create an Apex Class to generate a custom search token, and you can skip to step 5.

Step 1: Create an Apex Class to Generate the Search Token

  1. In Salesforce, access the Developer Console.

  2. In the Developer Console, create a new Apex class ( File > New > Apex Class).

  3. In the new Apex class, enter the following template:

     public with sharing class <MY_APEX_CLASS> {
         // Annotate the method so that it's accessible from the Lightning component
         @AuraEnabled
         public static string getToken() {
             // Generate a token using the Globals class provided by Coveo.
             // See the Globals Class documentation: https://docs.coveo.com/en/1075/coveo-for-salesforce/globals-class
             Map<String, Object> endpoint = CoveoV2.Globals.getEndpointData();
             endpoint.put('token', CoveoV2.Globals.generateSearchToken());
             return JSON.serialize(endpoint);
         }
     }

    Where you replace <MY_APEX_CLASS> with the name you chose for your Apex class.

  4. In the getToken() class, enter your code to create the custom search token. Modify that code to at least include the searchHub in your token generation steps.

    Warning

    For content security reasons, don’t specify a search hub value as a parameter of the getToken() class (e.g., getToken(String searchHub).

    Example
    public with sharing class <MY_APEX_CLASS> {
        // Annotate the method so that it's accessible from the Lightning component
         @AuraEnabled
         public static string getToken() {
             // Generate a token using the Globals class provided by Coveo.
             // See the Globals Class documentation: https://docs.coveo.com/en/1075/coveo-for-salesforce/globals-class
            Map<String, Object> endpoint = CoveoV2.Globals.getEndpointData();
            endpoint.put('token', CoveoV2.Globals.generateSearchToken(new Map<String, Object> {
             'searchHub' => '<MY_SEARCH_HUB>'
             }));
            return JSON.serialize(endpoint);
        }
    }

    Where you replace <MY_SEARCH_HUB> with the name of the search hub to enforce in the search token.

    Note that you can specify other parameters in the search token, such as query filters or a query pipeline.

    See Globals Class for instructions.

  5. Save the Apex class.

Step 2: Create the Custom Lightning Endpoint Handler

Now that you have created your Apex class, you must create a custom Lightning endpoint handler to reference your Apex class in your Lightning component.

  1. In the Developer Console, create a Lightning component.

  2. In the component .cmp, add the following code:

    <aura:component controller="<MY_APEX_CLASS>" >
        <!-- GET THE ENDPOINT INITIALIZATION DATA -->
        <aura:method name="getEndpoint" action="{!c.getTokenAction}" access="global">
            <aura:attribute name="name" type="String" />
        </aura:method>
        <!-- RENEW THE ENDPOINT ACCESS TOKEN -->
        <aura:method name="renewAccessToken" action="{!c.getTokenAction}" access="global">
            <aura:attribute name="name" type="String" />
        </aura:method>
    </aura:component>

    Where you replace <MY_APEX_CLASS> with the name of the Apex class you created in previous step.

  3. In the controller.js file, enter the following code:

    ({
        getTokenAction: function(component, event, helper) {
            const getTokenAction = component.get('c.getToken');
            var getTokenPromise = new Promise(function (resolve, reject) {
                getTokenAction.setCallback(this, function (response) {
                    if (response.getState() === 'SUCCESS') {
                        var responseData = response.getReturnValue();
                        resolve(JSON.parse(responseData));
                    } else if (response.getState() === 'ERROR') {
                        reject(Error('Error generating token'));
                    }
                });
            });
    
            $A.enqueueAction(getTokenAction);
            return getTokenPromise;
        }
    });
  4. Save the file.

Your custom Lightning endpoint handler is now ready.

Note

In our simple example, since there’s no difference between the generation and the renewal of a token, we call the same controller.js method twice.

Step 3: Reference the Custom Lightning Endpoint Handler in a Recommendations Component

Now that you have created your Apex class to generate a custom search token and a custom Lightning endpoint handler, you must reference the custom Lightning endpoint handler in a Recommendations component.

Note

The following procedure assumes that you have created a custom Coveo Recommendations component as the default Coveo for Salesforce Recommendation Lightning Web component doesn’t support custom search tokens. See Creating Your Custom Component for instructions on how to create a custom Recommendations component.

  1. In Salesforce, access an existing custom Lightning component, or create a new one.

  2. In the component .cmp, ensure that your component references the custom Lightning endpoint handler you created in the last step. For example, the component .cmp should look like the following:

    <aura:component implements='forceCommunity:availableForAllPageTypes' access="global">
        <aura:attribute name="endpointHandler" type="Aura.Component[]" access="global">
            <c:<MY_CUSTOM_ENDPOINT_HANDLER>></c:<MY_CUSTOM_ENDPOINT_HANDLER>>
        </aura:attribute>
      <aura:attribute name="title"
                      type="String"
                      access="global" />
      <aura:attribute name="debug"
                      type="Boolean"
                      default="false"
                      access="global" />
      <aura:attribute name="recommendationsContext"
                      type="String"
                      access="global" />
      <div>
          <article>
              <header>
                   <h2>
                       {!v.title}
                   </h2>
              </header>
               <CoveoV2:SearchUI endpointHandler="{!v.endpointHandler}"
                     name="<VISUALFORCE_COMPONENT_NAME>"
                     debug="{!v.debug}"
                     aura:id="coveoRecommendations" />
          </article>
      </div>
    </aura:component>

    Where you replace <MY_CUSTOM_ENDPOINT_HANDLER> with the name of the custom endpoint handler you created in the last step and <VISUALFORCE_COMPONENT_NAME> with the name of the Visualforce component that contains the JavaScript configuration for your custom Recommendations component (see Leveraging JavaScript Search Framework Components for more information).

  3. Save the Lightning component.

Step 4: Ensure Your Recommendations Component Generates the Search Token Server Side

The Recommendations component inherits its configuration from the Community Search component if they share the same name.

Therefore, any change made to the Advanced Server-Side Configuration panel, such as activating the Bypass above settings to rather generate the search token from a custom Apex class option will be replicated in your Recommendations component’s configuration.

Step 5: Validate the Search Token

Now that you’re enforcing configurations in a search token that’s generated server side, you should validate that the search token enforces the proper parameters to ensure that your content filtering is secure.

  1. Access the Salesforce Community where your custom Coveo Lightning Recommendations component is integrated.

  2. Access the Preview mode.

  3. Open the Debug panel for the custom Coveo Lightning Recommendations component, and then select the Enable query debug option.

  4. Search for the Pipeline parameter, and verify whether the associated value represents the query pipeline to which queries must be directed.

Configure the Search Token for a Quantic Search Interface

Step 1: Modify Your Token Provider

In most Quantic implementations, you will have installed and configured the Coveo for Salesforce package, and you will have used it to implement your search token provider. If that’s the case, enforcing a target search hub requires minimal configuration of this search token provider. Hardcode the target search hub when calling the generateSearchToken function:

global with sharing class CoveoTokenProvider implements ITokenProvider {
  @AuraEnabled(continuation=true cacheable=false)
  global static String getHeadlessConfiguration() {
    Map<String, Object> coveoEndpointData = CoveoV2.Globals.getEndpointData();
    String searchToken = CoveoV2.Globals.generateSearchToken(new Map<String, Object> {
      'searchHub' => '<TARGET_VALUE>'
    });
 
    Map<String, String> headlessConfiguration = new Map<String, String>();
    headlessConfiguration.put('organizationId', (String) coveoEndpointData.get('organization'));
    headlessConfiguration.put('accessToken', searchToken);
    headlessConfiguration.put('platformUrl', (String) coveoEndpointData.get('clientUri'));
    return JSON.serialize(headlessConfiguration);
  }
}

Where you replace <TARGET_VALUE> by the target search hub value.

Warning

The reason why it’s important to hardcode the target search hub value in your backend function (e.g., getHeadlessConfiguration()) is that you don’t want its output to depend on a parameter (e.g., getHeadlessConfiguration(hub)), because malicious users could leverage that parameter to modify the search hub value set in their token, potentially causing security issues.

If you have not installed the Coveo for Salesforce package, or you have decided to implement your own custom token provider for some other reason, we can’t make precise recommendations about what to do, but be sure not to expose an argument that would allow users to modify the search hub value set in the token.

Note

In a Quantic search interface, while search tokens can enforce a search hub in search requests, you should also set your QuanticSearchInterface component searchHub parameter to the target search hub value, as this is the parameter used to log usage analytics data.

<c-quantic-search-interface engine-id={engineId} search-hub="<TARGET_VALUE>"></c-quantic-search-interface>

Where you replace <TARGET_VALUE> by the target search hub value.

Step 2: Validate the Search Token

Now that you’re enforcing configurations in a search token that’s generated server side, you should validate that the search token enforces the proper parameters to ensure that your content filtering is secure.