Custom Salesforce Auth. Provider for Microsoft Azure client_credentials flow

When doing integrations from Salesforce you sometimes need to do this using single identity instead as in the context of the current user. Salesforce supports both through Named Credentials i.e. both working as the current user or as a Named Principal. Through the Named Credentials and Auth. Provider concepts from Salesforce you can setup a connection between Salesforce and an OAuth 2.0 enabled endpoint such as Microsoft Azure i.e. if needing the access the Microsoft Graph API. This can however be an issue as the target system (i.e. Microsoft Azure in this case) may not use a user that is able to login or you may not want to use a user license in the target system.

In this case you might want to use the client_credentials OAuth flow as that identifies the caller using a client_id and a client_secret instead of a user id. Unfortunately that OAuth flow type is not supported out-of-the-box with Salesforce. The reason is that the Auth. Providers in Salesforce usually deals with a user behind the keyboard. Due to this the OAuth 2.0 Auth. Provider flows was designed for a access_token / refresh_token World. This makes it impossible to use the built in capabilities for the client_credentials flow.

The solution is to write a custom Auth. Provider in Apex and use that from your Named Credential. To make this easier I’ve already implemented this for you. The code is available on Github in my salesforce-azure-clientcredentials-authprovider repo. This implementation just plays along with the access_token / refresh_token requirements and just requests a new access_token using the client_credentials flow whenever a (new) access_token is needed and hence do not need a user behind the keyboard.

The README.md in the repo has instructions for installing and configuring the code in the org. Once deployed you can create an Auth. Provider and a Named Credential. Please note you also need to create an App Registration in Azure Active Directory with the required Application Permissions.

Remove all padding in a Salesforce Experience Cloud Site

Note to self. When building non-LWR based Experience Cloud sites there is some padding that needs to be removed to make your site fill the entire display port. Put the following CSS classed in custom CSS for the Site to remove it.

.cCenterPanel {
padding: 0px;
margin: 0px;
}
.contentRegion {
padding: 0 !important;
}

YMMV

Minimum access to create/delete Salesforce scratch orgs

Working with scratch orgs in Salesforce requires that the DevHub feature is enabled in a non-sandbox (i.e. Production, Developer or Trial) org and that you’ve authenticated to the org. Normally from your Salesforce CLI or CI/CD pipeline.

Since the DevHub is required to be enabled in Production this has led to some concern from some customers I’ve spoken to. Following up on this with a customer who now really needed the scratch org capability I set out to figure out the least amount of access required to the DevHub Salesforce org.

It’s important to remember that license is one thing another is object access. If you are out of licenses Salesforce

Well one thing is license another is access. License seems well described but not so access. Played a bit around with access and was able to get it working with minimum access to an org. I started with a no-access profile and added API access and then figured out object access required. Minimum access required to create a scratch org is:
Read, Create on ScratchOrgInfos
Read on ActiveScratchOrgsTo delete a scratch org you need:
Read, Create, Edit on ScratchOrgInfos
Read, Create, Edit, Delete on ActiveScratchOrgs

Unable to force:source:push ExperienceBundle from API version 50.0 with API version 51.0

Yesterday I was trying to deploy some source including an Experience Cloud Site (using ExperienceBundle) created with API version 50.0 to a scratch org but it failed when I updated the API version to 51.0 in sfdx-project.json . Deploying with API version 50.0 worked just fine. The deploy (w/ API version 51.0) failed with the following message:

Error  force-app/main/default/experiences/Digital_Capability_Assessment_Aura1.site-meta.xml  You seem to be missing the property configurationTags in Digital_Capability_Assessment_Aura1/routes/register.json with component ID: f7c5ea49-0bde-4848-a72f-82ace4ea6760

And the error message was right – that key is not in the file but that’s was also true for some of the other Experience Cloud files. Deploying with API version 50.0 and trying to pull with API version 51.0 didn’t change any source. Clever people told me that this was expected as nothing changed in the org (regardless of a publish or similar).

Solution was to deploy with force:source:push with API version 50.0 and then do a force:source:retrieve specifying API version 51.0 on the command line. Then afterwards toggle the API version in sfdx-project.json.

sfdx force:source:retrieve -u dca_scratch_comm -a 51.0 -m ExperienceBundle

Turning on trace debugging with the Salesforce CLI

When using the Salesforce CLI as the primary way to interact with a scratch org turning on Apex trace debugging can be a tiresome-I-have-to-click-into-the-org situation. Usually you are not able to use force:apex:log:list and force:apex:log:get commands to work with Apex logs without first opening the Web Developer in the org or setting up trace logging.

But it turns out there is a better way using a simple script.

The below script does the trick for you can easily be added to your process for creating new scratch orgs. The script sets up some timestamps and then queries for the scratch org user userId. Then we get the Id of the trace log configuration for the user and then updates the record to enable trace logging for 24 hours.

NOW=`date -u +"%Y-%m-%dT%H:%M:%SZ"`
EXP=`date -v+24H -u +"%Y-%m-%dT%H:%M:%SZ"`

USERID=`sfdx force:data:soql:query -q "select id,name from user where name='User User'" --json | jq ".result.records[0].Id" -r`

TRACEID=`sfdx force:data:soql:query --query "SELECT Id, DebugLevel.DeveloperName, ExpirationDate, TracedEntityId FROM Traceflag WHERE TracedEntityId IN (SELECT ID from USER WHERE ID = '${USERID}')" --usetoolingapi --json | jq ".result.records[0].Id" -r`

sfdx force:data:record:update --sobjecttype TraceFlag --sobjectid $TRACEID -v "StartDate=$NOW ExpirationDate=$EXP" --usetoolingapi --json --loglevel fatal

The above script uses jq (https://stedolan.github.io/jq/) for JSON parsing and works on Mac (date command switches is slightly different on Linux) so YMMV.

Salesforce API Postman Collection

If you develop with the Salesforce API’s the following will save you a lot of time and make your life a lot easier. In our ongoing effort to make the Salesforce API’s easier to consume our Developer Relations have built a Postman Collection with 200+ requests. I know I’ve spent a lot of time to maintain my own collection for demos – that time is over!

The collection covers the following Salesforce APIs:

  • Auth
  • Bulk (V1 & V2)
  • Async Query
  • Rest
  • UI
  • Tooling
  • Metadata
  • Composite
  • Chatter
  • Connect

The collection and instructions are available on Github and there is even a webinar to help you get going.

Time Warp now on the AppExchange

For a while you’ve been able to install the #AWESOME timeline Lightning Web Component from Github (https://github.com/deejay-hub/timeline-lwc) into any Salesforce org using CLI tools or similar. Besides being an awesome example how just how nice components you can build with Salesforce it also serves as nice addition to any org to provide nice visualizations.

It just came to my attention that the component has been renamed to Time Warp and is available on the AppExchange (https://appexchange.salesforce.com/appxListingDetail?listingId=a0N4V00000GXVf4UAH). w00t! Being on the AppExchange makes it even easier to install and I highly recommend you take a look at this awesome component.

Image from Github, https://github.com/deejay-hub/timeline-lwc

(Image from Github, https://github.com/deejay-hub/timeline-lwc)