Introduction
In this blog, I am going to explain how to set up salesforce canvas signed the request with node js. Signed Request is default authentication for canvas app. The signed request authorization flow varies depending on whether the canvas app’s Permitted Users field is set to “Admin approved users are pre-authorized” or “All users may self-authorize”. The signed request containing the consumer key, access token, and other contextual information is provided to the canvas app if the administrator has allowed access to the canvas app for the user or if the user has approved the canvas app via the approve/deny OAuth flow
Setup Connected App
First, we are going to create a connected app to obtain the consumer secret key which we will be used in the signed request.
- In Salesforce, from Setup, enter Apps in the Quick Find box, then select Apps.
- In the Connected Apps related list, click New.
- In the Connected App Name field, enter NodeJsSignedRequest.
- In the Contact Email field, enter your email address.
- In the API (Enable OAuth Settings) section, select the Enable OAuth Settings field.
- In the Callback URL field, enter https://localhost:8443/sdk/callback.html.
- In the Selected OAuth Scopes field, select Full Access.
- In the Canvas App Settings section, select Force.com Canvas.
- In the Canvas App URL field, enter https://localhost:8443/
- In the Access Method field, select the Signed Request (Post).
- In the Locations field, select Chatter Tab and save it.
On the detail page for the canvas app, next to the Consumer Secret field, click the link Click to reveal. The consumer secret is used in the app to authenticate. We will configure the this later in the Heroku apps.
Configure Who Can Access the Canvas App
Now you need to configure the canvas app for the user access
- go to “NodeJSSignedRequest” managing connected apps and click on manage and edit policies
- In the Permitted Users field, select “Admin approved users are pre-authorized.” and then save it
3. In the Profiles related list, click Manage Profiles.
4. Select the System Administrator profile and click Save.
Time to Code
1 .create a package.json file as shown below
{ "name": "signedrequest", "version": "1.0.0", "description": "", "main": "index.js", "dependencies": { "express": "~4.8.1", "body-parser": "~1.2.2", "request": "~2.36.0", "ejs": "~1.0.0", "crypto-js": "^3.1.6" }, "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", "license": "ISC" }
2.create index.js file as shown below
var express = require('express'), bodyParser = require('body-parser'), path = require('path'), CryptoJS = require("crypto-js"); var app = express(); var consumerSecret = process.env.CANVAS_CONSUMER_SECRET; app.use(express.static(path.join(__dirname, 'views'))); app.set('view engine', 'ejs'); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ entended: true })); app.get('/', function (req, res) { res.render('index'); }); app.post('/', function (req, res) { var signed_req = req.body.signed_request; var hashedContext = signed_req.split('.')[0]; var context = signed_req.split('.')[1]; var hash = CryptoJS.HmacSHA256(context, consumerSecret); var b64Hash = CryptoJS.enc.Base64.stringify(hash); if (hashedContext === b64Hash) { res.render('index', { req: req.body, res: res.data }); } else { res.send("authentication failed"); }; }) var port = process.env.PORT || 9000; app.listen(port); console.log('Listening on port ' + port);
3. create the index.ejs view inside the “views” folder.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> </head> <body> <%- JSON.stringify(req) %> </body> </html>
4. Create Profile to host it to Heroku
web: node index.js
5. Run the following commands from the terminal.
heroku login git init git add . git commit -m "Commit" heroku create git push heroku master
6. Set the environmental variable to Heroku app. we are going to set the environmental variable with consumer secret which we got in the connected app.
heroku config:set CANVAS_CONSUMER_SECRET=2781208380818866866
7. Now you will see Heroku app URL some think like https://arcane-woodland-93536.herokuapp.com/ .
8. Go to the connected app and edit and replace OAuth callback URL and canvas app URL with Heroku app URL.
9. Now if you can go to chatter page you see the canvas app is returning the response with SignedRequest.
What Signed Request Contains?
The signed request is a string of the following elements concatenated
- The canvas app consumer secret encrypted with HMAC SHA–256 algorithm
- A period (“.”)
- The context and authorization token JSON encoded in Base64
When using a signed request, Salesforce delivers the user context and authentication information to your canvas app URL. To ensure that the signed request is valid, you must verify that the signed request was signed using your specific canvas app consumer secret as explained below.
- Receive the POST message that contains the initial signed request from Salesforce.
- Split the signed request in the first period. The result is two strings: the hashed Based64 context signed with the consumer secret and the Base64 encoded context itself.
- Use the HMAC SHA-256 algorithm to hash the Base64 encoded context and sign it using your consumer secret.
- Base64 encode the string created in point 3.
- Compare the Base64 encoded string with the hashed Base64 context signed with the consumer secret you received in point 2.