Populating the user object with passport.js and Salesforce OAuth

Using passport.js is a great option for doing authentication in node.js applications with great strategies for authenticating through just about anything on the planet including Salesforce. Using passport.js with Salesforce involves using the OAuth2Strategy but the user object in the session is not usable really as I really want actual information about the user to be there. The solution I came up with was overriding the userProfile-method and adding a call to the Salesforce userinfo endpoint as shown below.

// configure authentication using oauth2
app.use(passport.initialize());
passport.serializeUser(function(user, done) {
    done(null, user.username);
});
passport.deserializeUser(function(login, done) {
    done(undefined, {
        "username": login
    });
});

OAuth2Strategy.prototype.userProfile = function(accessToken, done) {
    this._oauth2.get(`https://${process.env.SF_LOGIN_URL || "login.salesforce.com"}/services/oauth2/userinfo`, accessToken, function (err, body, res) {
        if (err) { return done(new InternalOAuthError('Failed to fetch user profile', err)); }
        try {
            let json = JSON.parse(body);
            let profile = {
                "provider": "Salesforce.com",
                "username": json.preferred_username,
                "name": json.name,
                "email": json.email,
                "firstname": json.given_name,
                "lastname": json.family_name,
                "payload": json
            };
            
            done(null, profile);
        } catch(e) {
            done(e);
        }
    });
}

passport.use(new OAuth2Strategy({
        authorizationURL: `https://${process.env.SF_LOGIN_URL || "login.salesforce.com"}/services/oauth2/authorize`,
        tokenURL: `https://${process.env.SF_LOGIN_URL || "login.salesforce.com"}/services/oauth2/token`,
        clientID: process.env.SF_CLIENT_ID,
        clientSecret: process.env.SF_CLIENT_SECRET,
        callbackURL: process.env.SF_CALLBACK_URL
    },
    function(accessToken, refreshToken, profile, cb) {
        cb(undefined, profile);
    }
));

The interesting piece is really the code in bold where I inject a call to /services/oauth2/userinfo to get information about the user and then add that as the user object.

Of course after having done all this I found passport-salesforce which is a strategy that does exactly the same thing – duh!!! Anyways it was fun to code it up.

Individual Object enablement in Salesforce Scratch orgs – now available!

I’m so happy that one of my scratch org pet peeves finally made it into the product for the Spring 19 release. It has not been possible to enable the Individual Object when creating new scratch orgs and IMO this has been lacking and a cause for many issues, discussions and workarounds in customer projects. But all this is a thing of the past now! Starting Spring 19 you may add the below orgPreferenceSetting to your scratch org definition file:

"settings": {
    "orgPreferenceSettings": {
      "consentManagementEnabled": true
    }
 }

Now the setting hasn’t made it into the documentation as of this writing but I know that it’s in the works. No go and create scratch orgs with the Individual Object enabled!

Further reading:

Salesforce Canvas Apps

A Salesforce Canvas app is an often overlooked easy way to integrate existing apps into Salesforce. A Canvas app is inlined into the Salesforce user interface and it requires only a very small change to your app to have it play nice with Salesfore. In theory you could get away without any change but usually you’d like to know who the calling user is. What’s really great about a Canvas App is that this information is POST’ed to the application at invocation together with an OAuth access_token to allow authenticated callbacks to Salesforce. To implement this you need to:

  1. Support POST at a URL you specify
  2. Render the application from here or redirect the user after the POST has been received
  3. Receive and handle the signed request

The signed request is a base64 encoded blob in two parts separated by a period. It looks very much like a JSON Web Token (jwt). To verify it you compute keyed hash (hmac) using the sha-256 algorithm with the client secret of the Connected App from Salesforce being the secret. Doing this in node.js is done like so:

const ourSignature = Buffer.from(crypto.createHmac(algorithm, clientSecret).update(objPart).digest()).toString('base64')
The algorithm is “sha-256”, the client secret is a string and objPart of the object part of the signed request.
To make it even easier I’ve created a repo showing how it’s done in node.js in an Express app. The source including an example app is available at https://github.com/lekkimworld/salesforce-oauth-express-middleware. The repo also contains a test app (canvas-test-app) that is easily deployable to Heroku.

Salesforce DX error output will go to stdout starting with v45

Now this is very good news for us that are doing scripting with Salesforce DX. Currently the Salesforce DX CLI (sfdx) will send its output to stdout (standard out) when the command succeeds and to stderr (standard error) if the command fails. Why would a command fail? Well if you try and describe an org with a wrong or non-existing alias that’s one reason.

Now this is really the expected behaviour for a CLI but when doing scripting using the –json flag to always have the response returned as JSON it just makes it more complicated. For one the response already have a “status”-flag to indicate whether the invocation was successful or not. Secondly having to deal with stdout and stderr is not difficult but leads to boilerplate scripting code as what you really want to do is capture the response and check that “status”-flag in the JSON. Also it makes it harder to adopt for people new to CLI scripting and the way it’s done across platforms differ.

Now to the good news.

As of v44, there is an environment variable to have all JSON output go to stdout. Set SFDX_JSON_TO_STDOUT=true to get this new behaviour. This will become the default behaviour in v45. Now it’s not listed on the environment variables list for Salesforce DX yet but I trust it will be soon.

Yay!! 🙏

 

Time for another change

It’s been almost two years since I threw the hat back over the wall and faced the challenge of leaving the comforts of my old job and community behind and join Salesforce as a Technical Architect in CSG (the Customer Success Group; our professional services division).

The last two years have flown by and I’ve become proficient and 6 times certified on Salesforce. I’ve spent loads of time at customer sites and learnt a lot from it and what challenges our customers are facing and why they’re choosing Salesforce. Although my time in CSG have been rewarding, challenging and educational it’s time for something new starting Monday 1 October.

Now I will not be leaving Salesforce as I’ve been able to find a really cool new position internally. Starting Monday I’ll leave CSG and switch to pre-sales and become a Cloud Architect. I’m very excited about this move. As a Cloud Architect I’ll be part of the greater pre-sales Solution Engineering team but instead of focusing on a specific cloud (Service Cloud, Sales Cloud, Marketing Cloud or Commerce Cloud) I’ll be part of a team that helps out with all the “technical stuff”. That means AppDev on our core Lightning Platform, Heroku, IoT, integration, security etc. It means helping out on sales opportunities and showing our customers or soon-to-be customers how they too can leverage the power of the Salesforce Platform to make them successful.

I’ve spent the last time dialling down my engagement with the customer I’ve been at since late April and only had sporadic contact with my new team. But although the contact have been sporadic I cannot wait for Monday and to get going. I already have public speaking engagements lined up and I’m looking very much forward to picking up public speaking again in my new role.

Wish me luck.

/m

jq and multi-field output to CSV

jq is some of the most underrated tools out there I think. It’s a command line JSON parser that makes it super easy to work with JSON on the command line and in turn makes developing small SalesforceDX tools a breeze. Today I needed to generate a CSV file of all fields from different objects for the integration team that doesn’t have access to Salesforce. Doing the describe is easy using the Salesforce REST API but when using jq different are usually on different lines like below (-r is a nifty switch for getting raw, unquoted strings).

$ sfdx force:schema:sobject:describe -s Account -u myorg --json | jq -r ".result.fields[] | .label, .name"
Age
Age__pc
PO Box
PO_Box__pc
Postal Code Before City
Postal_Code_Before_City__pc
Street No Before Street
Street_No_Before_Street__pc
Archived State
Archived_State__pc

The output is almost what I wanted but really wanted not  to have to edit the file manually to build the output. Some quick googling and it appears that jq supports both CSV and tabular output from arrays. So fixing the issue was as simple as follows:

$ sfdx force:schema:sobject:describe -s Account -u myorg --json | jq -r ".result.fields[] | [.label, .name] | @csv"
"Age","Age__pc"
"PO Box","PO_Box__pc"
"Postal Code Before City","Postal_Code_Before_City__pc"
"Street No Before Street","Street_No_Before_Street__pc"
"Archived State","Archived_State__pc"

This is so cool… Love it!!