kevinohara80 / nforce

nforce is a node.js salesforce REST API wrapper for force.com, database.com, and salesforce.com
MIT License
474 stars 167 forks source link

NForce Connection Issue #158

Closed scottmcconnell5 closed 6 years ago

scottmcconnell5 commented 6 years ago

I'm having issues connecting to Salesforce through my app. My goal is to create an account for the user when a button is clicked, and that the account is created by automatically logging into Salesforce using my own username/password/security token. My app is written in javascript/html/css and was created using Meteor. Here is the relevant code (all capitalized variables I have hardcoded with actual values):

case "SalesForceButton":
    var nforce = require('nforce');

    var org = nforce.createConnection({
        clientId: 'CLIENT_ID',
        clientSecret: 'CLIENT_SECRET',
        redirectUri: 'https://localhost:3000/oauth/_callback',
        environment: 'production',
        mode: 'single'
    });
    var username      = 'USERNAME',
    password      = 'PASSWORD',
    securityToken = 'SECURITY_TOKEN',
    oauth;

    org.authenticate({ username: username, password: password, securityToken: securityToken }, 
    function(err, resp){
        if(!err) {
            console.log('Access Token: ' + resp.access_token);
            oauth = resp;

            var acc = nforce.createSObject('Account');
            acc.set('Name', 'Spiffy Cleaners');
            acc.set('Phone', '800-555-2345');
            org.insert({sobject: acc}, function(err, resp){
                if(!err) console.log('It worked!');
            });
        } else {
            console.log('Error: ' + err.message);
        }

    });
break;

Things I've done: 1) Setup nforce properly (npm install nforce) 2) Created a connected app on Salesforce using the same redirect URI as above and https://localhost:3000 as the start URL 3) Whitelisted https://localhost:3000 in the CORS section in Salesforce 4) Put https://localhost:3000 in Remote Site Settings section in Salesforce 5) Done all the steps above but using a publicly hosted URL (https://www.my_company.com) 6) Used the "Access-Control-Allow-Origin" chrome extension (it shortened the second error below but console was still showing "Response to preflight request doesn't pass access control check: Response had HTTP status code 400."

Errors I'm getting: screen shot 2018-07-31 at 12 51 09 pm

Any help would be greatly appreciated. I can provide more information if needed. Thank you!!!

amazingjoe commented 6 years ago

You are white-listing/setting remote site settings with https but using http in your browser call. Make the local call is secure over https and I think it should work. Or use http instead of https inside of Salesforce.

Note that Salesforce may not be permitting http even for localhost. If they do allow for http whitelisting for localhost that would probably be the only exception allowed as they typically don't permit this.

scottmcconnell5 commented 6 years ago

I tried replacing all localhosts with a publicly hosted URL (and it shows the browser call with https), still nothing :(

screen shot 2018-07-31 at 4 53 13 pm

amazingjoe commented 6 years ago

Can you copy and paste everything in that last portion, some of it is truncated?

Also I am assuming in SF that you have opened access for nthround.io.

scottmcconnell5 commented 6 years ago

This screenshot shows that entire error, this is the error I get when I turn on my CORS enabling chrome extension. And yes, I made a Connected App and added my site url to the CORS and Remote Site Settings in Salesforce.

screen shot 2018-08-01 at 12 00 07 pm

scottmcconnell5 commented 6 years ago

I updated my code to follow after seeing this -

var nforce = require('nforce');

var org = nforce.createConnection({
    clientId: 'xxxxx',
    clientSecret: 'xxxxx',
    redirectUri: 'http://nthround.io/oauth/_callback',
    apiVersion: 'v36.0',  // optional, defaults to current salesforce API version
    environment: 'production',  // optional, salesforce 'sandbox' or 'production', production default
    mode: 'multi' // optional, 'single' or 'multi' user mode, multi default
});
var username      = 'xxxxx',
    password      = 'xxxxx',
    securityToken = 'xxxxx',
    oauth;
org.authenticate({ username: username, password: password, securityToken: securityToken }, function(err, oauth){
    // store the oauth object for this user
    if(err) return console.log('Error:' + err);
    var client = org.createStreamClient({ oauth });

    var acc = nforce.createSObject('Account');
    acc.set('Name', 'Spiffy Cleaners');
    acc.set('Phone', '800-555-2345');

    org.insert({sobject: acc}, function(err, resp){
        if(!err) console.log('It worked!');
    });
});

Now these are my only errors:

screen shot 2018-08-01 at 4 19 23 pm

Seems like I need to be initially authenticated before I make authenticated calls, but I'm not sure how to get authenticated!

amazingjoe commented 6 years ago

I think you might have just hit a F-cked up SF technical brick wall.

Take a look at the last post in this thread.

https://developer.salesforce.com/forums/?id=9060G000000XfhRQAS

Essentially you can set up your instance to whitelist the different domains etc... but the authentication server is not your server and not under your purview to whitelist on behalf of. Which sucks.

It looks like even people using Lighting Out (Salesforce Lighting Components served outside of Salesforce in Javascript) have to find a means around this to get a token.

Here is an example of one proxy that does so. I am betting there are probably prebuilt one button Heroku proxies you can find that will authenticate for you and return the token.

This link has some information on how to get authenticated but it involves setting up nodejs etc.... to do so. http://cloudyworlds.blogspot.com/2016/03/taking-your-lightning-components.html

So essentially it looks like you need to use a proxy to get your tokens and leverage CORS to avoid using a proxy.

https://stackoverflow.com/questions/29670703/how-to-use-cors-anywhere-to-reverse-proxy-and-add-cors-headers

Now since you probably don't want to do all that work I think you could leverage a CORS Proxy to perform the authentication and get your token and then after that you should be good to go hopefully. You will need to set up the authentication for the remote app and whitelists for the proxy server I am thinking.

scottmcconnell5 commented 6 years ago

@amazingjoe Thank you so much for all this information!! I've spent some time today trying to do what you described, but I still haven't been able to get it running. I followed the instructions laid out in your third link, but I still have a few questions... Do I need to set up my app with Heroku to do this? Or can I just use a CORS proxy to perform the authentication? If I can just use a proxy, I found a promising one here but I've never used a proxy so I'm having trouble. It asks for my sessionID, but how do I get that?

amazingjoe commented 6 years ago

@scottmcconnell5 Ok scratch my last comments. I think i sent a link to a proxy with the same issue as the prior one. You still need to get the session ID.

Here are some links that I think can help:

In each of these scenarios you are going to need to install NodeJS so your computer is acting as a backend and serving the page (gets around CORS). Then once you are able to capture the token you could then use it with your script to do everything client-side.

Or perhaps you may want to just do everything with NodeJS and then call your NodeJS from your clientside Javascript to get the data and have the NodeJS do all the Salesforce work.

In production you would want to have a place like Heroku to park the proxy.

scottmcconnell5 commented 6 years ago

So I found what looks to be an easy-to-install proxy with a Deploy To Heroku button here, but I'm getting confused with which URL's to put where. If my app is hosted at nthroud.io and I want to be able to connect to the proxy through my app, how should I set my Connected App start url and callback uri? The directions just say to put "xxxx.herokuapp.com" but I'm not sure what to put in for the x's.

In my heroku proxy app, when I set the callback uri to https://nthround.io.herokuapp.com/oauth/_callback and launched the app, it actually logs me to salesforce, but then it leads me to https://nthround.io.herokuapp.com/oauth/_callback, where it just shows:

screen shot 2018-08-03 at 11 43 51 am

If I try to change my callback uri in Heroku to something different, it gives an error when logging into Salesforce.

Should I now push my app's github repo to this Heroku app? When I tried doing that before, it would give me an error when deploying...

I was imagining that this heroku proxy app would be separate, and that I wouldn't need to push my code to it, but I could be wrong.

kevinohara80 commented 6 years ago

Going to close this since there doesn't seem to be an nforce issue. Please re-open if I'm wrong :)