Josh Windsor Josh Windsor - 23 days ago 10
reST (reStructuredText) Question

Suggestions for Authenticating between applications (Salesforce ->Heroku)

I have been struggling over the past week to get the ideal configuration for my implementation. Basically, I have a Salesforce Page which makes a REST callout containing some data to be computed, A Heroku server then computes this data before sending the computed data back to SF in the response. This all happens in the background and so no Heroku front end exists.

I want to protect this callout with oAuth2, but I'm not sure the best way to do it:

The data itself is not important, its the access to the heroku app which is.

If I use salesforce for authentication, it means that the callout structure doesn't work (I would have to implement a system for Heroku to grab the data from SF before returning it) which isn't ideal and I can't see a way to use Heroku authentication as it allows access to the api but not the app script in a single structure. I think I have to create my own authentication server within Heroku but I'm not exactly sure if this is the correct way of going about it.
Any tips would be greatly appreciated

This is my callout code from SF:

Http http = new Http();
HttpRequest request = new HttpRequest();
//Sets the url to heroku
request.setEndpoint('My App URL');
request.setMethod('POST');
request.setHeader('Content-Type', 'application/json');
//places the content into the body
request.setBody(content);
//Extends the read timeout
request.setTimeout('120000');
//Sends the request and waits for a response
HttpResponse response;
response = http.send(request);


Heroku Side:

post("/", (req, res) -> {
//creates a local var for the JSON string
String data = req.body();
//--** The server then computes this data and calculates output
String computedData = compute(data);
return computedData;
});


I need a way of authenticating this type of connection, Thanks!!!

Nio Nio
Answer

Did you read the Heroku guide to OAuth? It's pretty helpful. The flow would be:-

  1. Salesforce app issues a redirect to your Heroku - GET https://id.heroku.com/oauth/authorize?client_id={client-id}&response_type=code&scope={scopes}&state={anti-forgery-token}
  2. After user has authorized access there is a callback to your Salesforce app with an exchange token
  3. You Salesforce app then needs to exchange the token for an Access token with your Heroku app with the relevant scopes to access the data at Salesforce

I'm not sure if this is what you want though since the whole point of OAuth is not authentication but authorization ie. the OAuth flow is not designed to identify the user, but to enable you client (Salesforce in this case) to access the user's resources held by the provider (your Heroku app in this case).


Since you want Authentication, not Authorization, there are a couple of approaches you could take depending on how much work you want to put in vs how secure it needs to be (you have to make a call on this).

  1. Quick and dirty but not very secure

    You could just check the referrer Header on Heroku and if the client is anything other than your Salesforce app then you return a 403 Forbidden or 401 Unauthorized. It's not very reliable since referrer is not overly reliable but its quick and straightforward if you do not have a great understanding of authentication and just want something quick and basic.

  2. Send a client ID with each request

    This could be a Header or be in the body of the request. For it to be secure though you will need to encrypt it since you say you do not want to use SSL/TLS. So you will need to encrypt/decrypt the client ID at each end.

    A basic approach is to just use some symmetric key that you share between your client (Salesforce) and provider (Heroku) which you store securely within each app somewhere so that hackers cannot read it. You also share (and securely store) some ID string (ideally some long random hash).

    The flow would go like this:-

    1. Salesforce app takes the random ID string and uses the symmetric key to encrypt it. This is what you send in the request to your Heroku app.

    2. Heroku app - on receiving an incoming request - reads the encrypted value. It then uses the symmetric key to decrypt it. Your Heroku app then compares the decrypted value passed in the request and the random ID string (it also has stored locally) and if they are the same you have some degree of confidence that the source of the request was your Salesforce app. If not you deny the request.

Authentication is a big subject, as is encryption. If you really need to protect the data and there is a risk of you being sued if you do not, then you need to do some more research. If the data is not sensitive (or particularly valuable to anyone else) and you are just trying to have some basic front gate which reduces other applications from exerting a load on your application then you could consider just checking the referrer as a first attempt.