Using Heroku Postgres in Private Space from Data Cloud

This post is mainly a note-to-self kind of thing… When using Heroku Postgres in a Private Space data in Data Cloud you need to use mTLS to connect, enable external connections (by default private space Heroku Postgres plans are only accessible inside the space) and whitelist the IP’s connecting to Heroku Postgres.

Steps are as follows:

  1. In Data Cloud Setup find your Data Cloud “Home Org Instance” as this will tell you where the instance is hosted. This will be something like CDP2-AWS-PROD1-USEAST1. Once you have it refer to the documentation for the IP addresses to whitelist in CIDR format. As of this writing the IP addresses are: “54.204.177.212/32”, “35.153.189.123/32”, “54.82.22.132/32”, “54.87.94.242/32”, “52.200.70.195/32”, “3.223.146.214/32”.
  2. Now refer to Connecting to a Private or Shield Heroku Postgres Database from an External Resource to configure external access to your Heroku Postgres plan. Once you’ve enabled it download the mTLS key and certificates (a bundle of 3 files).
  3. Update the IP whitelist for the Heroku Postgres instance using the Heroku CLI or the Dashboard. I find using the CLI the easiest. To do this you need the app name from Heroku (for this example young-reef-43874), the Heroku Postgres instance name (for this example postgresql-deep-41052) and the IP addresses to whitelist. Ensure you have the mTLS plugin installed as described in the article. Now add the IP addresses and remember you own for testing…
heroku data:mtls:ip-rules:create postgresql-deep-41052 --app young-reef-43874 --description "Data Cloud, US-EAST, CDP2-1" --cidr "54.204.177.212/32"
heroku data:mtls:ip-rules:create postgresql-deep-41052 --app young-reef-43874 --description "Data Cloud, US-EAST, CDP2-2" --cidr "35.153.189.123/32"
...
heroku data:mtls:ip-rules:create postgresql-deep-41052 --app young-reef-43874 --description "Data Cloud, US-EAST, CDP2-6" --cidr "3.223.146.214/32"
  1. Test the whitelisting with psql CLI – also nicely described in the documentation referenced above.
  2. Now go back to Data Cloud and configure the connector. You need both the certificates and the key from the bundle, the schema to connect, and database name and the username and password from the Heroku Postgres instance.

Spring 25 Walk-thru

When ever a new Salesforce release comes out I read through the release notes and make a note of what I think is important. I think I’ll start publishing those here.

Customization

Development

Einstein

Flow

Security, Identity and Privacy

PKCE in Apex

// generate code verifier
final String codeVerifier = EncodingUtil.base64Encode(Crypto.generateAesKey(256));

// generate code challenge (sha-256 hash of verifier and then base64url encoded)
final Blob bCodeChallenge = Crypto.generateDigest('SHA-256', Blob.valueOf(codeVerifier));
final String codeChallengePre = EncodingUtil.base64Encode(bCodeChallenge);

// base64url escape
final String codeChallenge = codeChallengePre.replaceAll('[+]', '-').replaceAll('[/]', '_').replaceAll('[=]', '');

Salesforce Certified JavaScript Developer I

PASS. The word you always look for on the confirmation page from Webassessor when you’ve completed an online proctored test for Salesforce. Happily I found the word and can now have another certification under my belt for the Salesforce platform.

I do not write this to brag about the passing the certification but rather to comment on it. The certification is made up of 2 parts. You complete the Lightning Web Components Specialist Super Badge on Trailhead and pass a multiple choice exam on Webassessor. The former part is for me the most interesting and was the most giving. The Super Badge is really nice and while we can always discuss how the challenges are checked I found it really worthwhile and a good experience. The multiple choice test requires you to have a firm grasp of the programming language, how it works and how promises, the task queue etc. actually work.

All in all a good experience that I would recommend.

Salesforce Headless Identity Login Example

This week I helped a colleague doing an example of how to use the Salesforce Headless Login flow from a single page app (SPA). The Github repo describes how to configure the Salesforce org (a scratch org) and how to use the included SPA – just a super simple HTML page really – to do a headless login against the Salesforce org. The login uses PKCE to further secure the exchange. Once the login has been performed the obtained access token is used to get information about the user from the /services/oauth2/userinfo endpoint.

YMMV

Salesforce Token Exchange Flow

I’ve spent some time with the new token exchange flow in Salesforce. The flow allows you to write and configure an Apex handler in Salesforce that can validate an incoming token (say an access_token, JWT or proprietary token) from another Identity Provider (think Okta, Auth0 or any custom implementation) in Salesforce and return a Salesforce access token that can be used towards Salesforce for API access. This can simplify the integration scenario for micro services or other apps as access can be granted based on an already proved identity. The returned Salesforce access token is then used for API access as the Apex handler also maps the incoming token to a user in Salesforce – the user may optionally be created on the fly.

I captured my findings, wrote instructions on how to implement wrote an example implementation in a Github repo.

As an interesting aside, the metadata type for the OAuth Token Exchange Handler is not yet supported with the “new” source format so it has to be deployed with the old school metadata API and format (still using the CLI though).

Scratch org with Salesforce Event Monitoring

Note to self – scratch org definition file to create a scratch org with Event Monitoring enabled. This is a super easy way to quickly spin up an org with Event Monitoring for testing or development. As always the trick is to know the feature and the settings to avoid the manual setup.

{
  "orgName": "foo",
  "edition": "Developer",
  "country": "US",
  "features": ["EventLogFile", "PersonAccounts"],
  "settings": {
    "lightningExperienceSettings": {
      "enableS1DesktopEnabled": true
    },
    "mobileSettings": {
      "enableS1EncryptedStoragePref2": false
    },
    "eventSettings": {
      "enableEventLogGeneration": true,
      "enableTransactionSecurityPolicies": true,
      "enableDeleteMonitoringData": true,
      "enableLoginForensics": true,
      "enableStreamingApi": true,
      "enableTerminateOldestSession": true,
      "enableDynamicStreamingChannel": false,
      "bypassMeteringBlock" :false
    }
  }
}

Scratch org with Salesforce Order Management

Note to self – scratch org definition file to create a scratch org with B2B Commerce and Order Management. The trick was to ensure Enhanced Orders was enabled as well.

{
  "orgName": "foo",
  "edition": "Enterprise",
  "release": "preview",
  "features": ["PersonAccounts", "B2BCommerce", "OrderManagement", "Communities", "EnableSetPasswordInApi", "SalesforceIdentityForCommunities", "Sites", "ExternalIdentityLogin"],
  "language": "en_US",
  "country": "US",
  "settings": {
    "lightningExperienceSettings": {
      "enableS1DesktopEnabled": true
    },
    "mobileSettings": {
      "enableS1EncryptedStoragePref2": false
    },
    "communitiesSettings": {
      "enableNetworksEnabled": true
    },
    "languageSettings":{
      "enableTranslationWorkbench": true
    },
    "commerceSettings": {
      "commerceEnabled": true
    },
    "orderManagementSettings": {
        "enableOrderManagement": true
    },
    "orderSettings": {
        "enableEnhancedCommerceOrders": true,
        "enableOrders": true
    }
  }
}