[SalesForce] How to call a Salesforce REST URL from Lightning Component

I want to call a Salesforce REST URL from a Lightning Component. Specifically, I'm trying to call this Analytics API URL: /services/data/v32.0/analytics/reports.

I see the following error in the JavaScript console:

Refused to connect to 'https://na15.salesforce.com/services/data/v32.0/analytics/reports' because it violates the following Content Security Policy directive: "connect-src 'self'".

I have a controller.js which calls to a helper.js which has the following in it in it. The sessionId is retrieved from an Apex controller that just returns UserInfo.getSessionId().

var action = component.get("c.getSessionId");
action.setCallback(this, function(a) {
    var sessionId = a.getReturnValue();
    console.log(sessionId);

    $j.ajax("/services/data/v32.0/analytics/reports", {
        beforeSend: function(xhr) {
            xhr.setRequestHeader("Authorization", "Bearer " + sessionId);
        },
        success: function(response) {
            alert('success!');
        },
        error: function(jqXHR, textStatus, errorThrown) {     
            alert(jqXHR.status + "," + textStatus + ": " + errorThrown);
        }
   }); 
});

$A.enqueueAction(action);

I'm positive that the REST request is valid as I'm able to make it successfully from a REST client (Postman).

I did see the Content Security Policy section in the Lightning Developer's Guide, but it doesn't seem to exclude Salesforce URLs:

The framework's CSP covers these resources:

JavaScript Libraries
All JavaScript libraries must be uploaded to Salesforce static resources. For more information, see Accessing JavaScript Libraries in Markup.

HTTPS Connections for Resources
All external fonts, images, frames, and CSS must use an HTTPS URL.

The security violation error message references a refusal to connect to na15.salesforce.com, even though I am just referring to a relative URL in the ajax call. Here is the csp report:

csp-report: {document-uri:https://na15.lightning.force.com/paura/widgets.app,…}
blocked-uri: "https://na15.salesforce.com"
document-uri: "https://na15.lightning.force.com/paura/widgets.app"
original-policy: "default-src 'self'; script-src 'self' https://ssl.gstatic.com/accessibility/ chrome-extension: 'unsafe-eval' 'unsafe-inline'; object-src 'self'; style-src 'self' chrome-extension: 'unsafe-inline'; img-src http: https: data:; media-src 'self'; frame-src https:; font-src https: data:; connect-src 'self'; report-uri /_/csp"
referrer: "https://na15.salesforce.com/_ui/common/apex/debug/ApexCSIPage"
status-code: 0
violated-directive: "connect-src 'self'"

Is it possible to access a Salesforce REST URL from a Lightning Component? If so, how and what am I missing?

Best Answer

Marty is correct, although I would like to temper the description of this being "unfortunate" a bit with some background on why the security policy is in place. In order for us to satisfy our internal security audits and architectural reviews which allowed us, for the first time ever in our presentation layer, to provide a supported mechanism to allow salesforce authored code and customer/ISV/partner authored code to coexist in the same JavaScript space we had to tighten things down significantly. Here are some of the things currently enforced:

  • Content security policy, or CSP, a relatively new browser technology that allows us to have fine-grained control over access to all external references to scripts, images, stylesheets, etc. Our policy is extremely restrictive right now and not extensible but we had plans to open up a white listing capability in the near future.
  • Lightning applications are served from a separate domain in much the same manner that visual force pages are today. The difference here is that you are actually in the same application, running right next to our client-side code and not relegated to live in an iframe silo. Those silos have presented significant challenges around producing high performance, high fidelity, engaging user experiences that integrates directly into core salesforce functionality for many years.
  • The lightning application separate domain also uses a special lightning session ID that does not have direct API access. The fact that you can currently provide indirect access to a fully API capable session ID is a great example of why our content security policy is currently so restrictive. Leaking an API said back to the client in a way that malicious JavaScript can easily steal is precisely why we have things locked down so tightly today. What should happen if you attempted to serialize an API session ID from an apex controller? That session ID is supposed to be the same restricted access Aura session ID but we apparently have a leak in that underlying logic. Our belt and suspenders approach with CSP combined with serving from a separate domain actually thwarted this potential attack.

Why did we do these things? Most of it boils down to "protect Setup". Without these safeguards in place is almost trivial for malicious client side code to gain height and privileges and access to administrative level functionality by remote controlling the setup user interface Also, much of what we have done so far represent cross site scripting (XSS) attack countermeasures.

There is definitely much more to the story but hopefully this gives you some of the back story to better understand our decisions and direction. This is not the end, rather just the beginning, and we are hard at work on improving and refining our approach to balancing the security requirements that we have to satisfy along with providing all of you with the tools that you need to build what you want.

Related Topic