Partager via


Solving cross-domain problems in apps for SharePoint

Hello there, I'm Humberto Lezama-Guadarrama, Program Manager on the Office Developer Platform team. In this post I will analyze some of the challenges that developers will likely face when building apps for SharePoint and how our cross-domain library and APIs can help you solve them.

Cross-domain, the eternal challenge

Almost all web developers have at some point in their career faced cross-domain problems while building web apps. In a nutshell, you encounter these type of issues whenever an app wants to make client-side calls (for example, using JavaScript + XMLHttpRequest) from a page hosted in one domain (for example, https://www.fabrikampapp.com/appPage.html) to a page or service hosted in a different domain (for example, https://contoso.sharepoint.com). By default, browsers block this type of communication for security reasons; they don't want malicious apps to grab data or execute code without users knowing it.

So, what's the big deal? Well, the very nature of the new app model for SharePoint encourages developers to host code outside of SharePoint (see hosting options), which means that, by design, apps will face cross-domain challenges.  You can use server-side code + OAuth to avoid cross-domain issues (because the communication in that case is server-to-server), but what if you want to use JavaScript?  We all love JavaScript don't we? :)

Cross-domain library for apps for SharePoint

There are many different techniques to overcome cross-domain issues in JavaScript, several of which are pretty hacky. The most robust solutions to date, that work in all major browsers, involve using the IFrame postMessage method to establish mutual trust between pages loaded from different domains. Technically, somebody writing an app for SharePoint could solve cross-domain problems on their own, but we wanted to provide a robust, secure library that app developers can take advantage of.

So, how does it work? The gist is that we take advantage of a really cool feature in apps for SharePoint named app webs. Essentially, every time an app is installed (and contains at least one artifact that is deployed into SharePoint, such as a blank page) a dynamic endpoint is created on the fly. This dynamic endpoint (the app web) has its own domain, which means that any client-side calls to it are automatically security trimmed so the app cannot ever elevate its privileges (and cause security issues).  What the cross-domain library does is that it creates a hidden Iframe that wires your remote page with a proxy page on the app web. We then use the IFrame postMessage method to relay the calls on the client side. This effectively enables you to securely make calls to SharePoint using JavaScript. Figure 1 summarizes this process.

clip_image002

Figure 1. Cross-domain library execution process

 

Wait a minute, but how does SharePoint know how to "trust" the external domain (for example, fabrikamappp.com in the Figure 1)? The answer is in the type of hosting that you are doing; cross-domain calls are supported for all types of hosting:

  • For SharePoint-hosted apps, you declare which domain to "trust" by using an internal app principal; you do this in the AppManifest.xml. This sounds a bit counterintuitive right? Why would you use a SharePoint-hosted app if you are going to host pages outside of SharePoint?  Well, because you need the app web to communicate back to SharePoint. To create an app web you have to host "something" on SharePoint, even if it's just a default page. You could of course also host more interesting things, like document libraries or lists, and use your remote page to access them.
    <AppPrincipal> <Internal AllowedRemoteHostUrl="https://fabrikamapp.com/appPage.html" /> </AppPrincipal>
  • For provider-hosted apps, SharePoint trusts the domain that you register as part of your OAuth registration (even if you don't actually use OAuth). Provider-hosted apps built for the marketplace use the seller dashboard to register their domain, as shown in Figure 2. For more details consult the guidelines for registering apps for SharePoint 2013.

clip_image004

Figure 2. Seller dashboard’s domain registration page

  • For autohosted apps, you don't have to worry about it. We automatically take care of registering the dynamically provisioned Azure website so you can use our library without any additional registration.

Sounds a bit complex, huh?  Well, it kind of is under the hood. But, actually using the cross-domain library after registering your external domain is pretty easy. You just have to reference our JavaScript library and initialize it, and then you're done.  Here's a snippet:

 // Load the cross-domain library. 
$(document).ready(function () { 
  var hostweburl; 
  var appweburl; 
  
  //Get the URI decoded URLs. 
  hostweburl = decodeURIComponent( getQueryStringParameter("SPHostUrl") ); 
  appweburl = decodeURIComponent( getQueryStringParameter("SPAppWebUrl") ); 
  
  // Load the .js files using jQuery's getScript function. 
  $.getScript(
    hostweburl + "/_layouts/15/SP.RequestExecutor.js",
    continueExecution
  );
  
  // After the cross-domain library is loaded, execution 
  // continues to this function. 
  function continueExecution() { 
    var executor; 
    
    // Initialize your RequestExecutor object. 
    executor = new SP.RequestExecutor(appweburl); 
    // You can issue requests here using the executeAsync method 
    // of the RequestExecutor object.
  } 
  
  // Function to retrieve a query string value.  
  function getQueryStringParameter(paramToRetrieve) {
    var params = document.URL.split("?")[1].split("&");
    var strParams = "";

    for (var i = 0; i < params.length; i = i + 1) {
      var singleParam = params[i].split("=");
      if (singleParam[0] == paramToRetrieve)
        return singleParam[1];
    }
  }
});

  

We have a detailed how to article that explains the cross-domain library and several samples for you to try right away. You might be pretty surprised about how quickly you can put something together.

Important Note: You may also face some challenges with Internet Explorer security features that prevent cross-internet zones from sharing cookies. The way this manifests itself is that the cross-domain library fails to load and you always get an error.  Solving this problem is pretty straightforward—the details of the issue and the resolution are documented in this article.

Cross-site collection calls

A different problem that is often lumped into the same cross-domain category is issuing calls to SharePoint across sites or across site collections. For example, an app installed at https://contoso.sharepoint.com/site1 wants to retrieve a list from https://contoso.sharepoint.com/site2.

On the surface this looks like a cross-domain problem, but it is not. It's actually a traversal problem inside SharePoint resources.  What you really want is for your app to talk to your allowed endpoint (your app web) and from there you want to internally proxy the call to a different site collection.

So, does that mean that you are out of luck if you want to use JavaScript?  Nope, we actually have a pretty handy object for you named AppContextSite.  All you have to do is set AppContextSite to point to the target web you want to talk to. Please note that in order for cross-site collection calls to work your app must be deployed as a tenant scoped app by an administrator; this is currently a security restriction of the API. Here is the syntax:

JSOM

Syntax:

 var ctx = new SP.ClientContext(appWebUrl);
var appContextSite = new SP.AppContextSite(ctx, targetUrl);
ctx.Load(appContextSite.get_web());

Example:

 var ctx = new SP.ClientContext(
  "https://contoso-5334ef4b86c8ea.sharepointonline.com/app1"
); //Get this from tokens instead of hardcoding it. 
var appContextSite = new SP.AppContextSite(
  ctx, https://contoso.sharepointonline.com/anothersite
); //Get this from user input or context tokens. 
ctx.Load(appContextSite.get_web());

 

REST

Syntax:

appWebUrl/_api/SP.AppContextSite(@t)/web?@t='targetUrl'

Full URL Example:

https://contoso-5334ef4b86c8ea.sharepointonline.com/app1/_api/SP.AppContextSite(\@t)/web?\@t='https://contoso.sharepointonline.com/anothersite'

 

Wow, that is a lot of info right? In practice though, it is pretty straightforward after you learn how the pieces fit together. In the vast majority of cases all you have to do is reference our cross-domain library and use it and you are good to go. If you do encounter issues, we are monitoring our support forums so feel free to ping us.

Happy coding!

Comments

  • Anonymous
    December 11, 2012
    What is the interplay here with Azure AD?  What if I write an app that is pulling content from a 3rd party solution that uses Azure AD for authentication.  What happens when the app is rendered inside of SharePoint Online?  What authentication is happening behind the scenes?  Does the session I have in IE pass through to the app, or is there another authentication that happens behind the scenes?

  • Anonymous
    March 07, 2013
    Jonty,  the techniques I described here allow your app to talk to SharePoint, there is no interplay with Azure AD.

  • Anonymous
    March 11, 2013
    in the target site collection the app try to access, how does it configure to allow the app to access the site collection?, or does it use the user's access to determine the access to target web?

  • Anonymous
    March 22, 2013
    Humberto, does this work with SharePoint 2010? I have an ASP.NET application on one web server, and I want it to access SharePoint (on another server) programmatically, to store and retrieve Excel and PDF documents. Both servers are in the same internal network, but they a in different Windows domains.

  • Anonymous
    April 11, 2013
    Humberto, just wanted to thank you for your fantastic article. very well written and informative. I loved this article :)

  • Anonymous
    July 03, 2013
    I'm trying to get some data from an other site collection than the hostweb using a sharepoint hosted app. I've tried your REST- and the JSOM-example above. But none of it works. This article on Sharepoint.Stackexchange declares the same problem (sharepoint.stackexchange.com/.../accessing-another-site-collection-from-a-sp2013-app). Do you have any advice?

  • Anonymous
    July 04, 2013
    Humberto, does this work for Outlook mail app.

  • Anonymous
    October 24, 2013
    cross domain in .net is working fine. but not wit share point. could u pls tell me the steps how can i proceed furthur...

  • Anonymous
    October 30, 2013
    Steffen, please note you need the app to be deployed as tenant scoped by an admin. This is currently a restriction of the API. The article has been updated to clarify this behavior.

  • Anonymous
    October 30, 2013
    Harpreet, depends on what you mean by "works" on a mail app :)  The library works on any webpage that talks to SharePoint as long as there is a corresponding SP app installed on the target (so it opens up the appweb). So if your mail app is reading information from SP, yes, you can use this library for that. If what you mean is using the library to talk to other services (not SP) then nope, it wasn't designed for that. Thanks!

  • Anonymous
    November 05, 2013
    Bob, this library only works with SharePoint 2013

  • Anonymous
    November 05, 2013
    Parham, thank you, glad you liked the article :)

  • Anonymous
    November 26, 2013
    Hi, the full URL Example link is not working

  • Anonymous
    November 27, 2013
    The comment has been removed

  • Anonymous
    November 27, 2013
    Is it possible to access a SharePoint custom web service from a SharePoint-hosted app within the same farm? I get an 'unauthorized' response. If I call an external web service such as services.odata.org/.../Categories the call is done successfully. We need to get some data (from host web) in elevated privileges, data which is displayed inside our app. Another thing we tried is to call a custom aspx from the host web in order to return some json. Neither approach is working and I can't find any solution to this problem. Is this possible, to somehow access host web data in elevated privileges from a SP-Hosted app? (I don't want to make the app a provider hosted app)

  • Anonymous
    December 09, 2013
    Hi Humberto, Thanks for the great article. You have mentioned that in javascript, app has to be deployed at tenant level for it to work. But the tenant level app share the same web. isn't it? So this is a restriction for now? Thanks.

  • Anonymous
    December 09, 2013
    As you gave as an example at the end of the article, I use REST query to get the items from a list in another site collection. http://appUrl/_api/SP.AppContextSite(@target)/web/lists/getbytitle('ListName')/Items?$select=Id,Title&$orderby=Title&@target='http://anothersitecollection&#39; I changed the app permission as follows. <AppPermissionRequests>    <AppPermissionRequest Scope="http://sharepoint/social/tenant" Right="Write" />    <AppPermissionRequest Scope="http://sharepoint/search" Right="QueryAsUserIgnoreAppPrincipal" />    <AppPermissionRequest Scope="http://sharepoint/content/tenant" Right="FullControl" />    <AppPermissionRequest Scope="http://sharepoint/content/sitecollection/web" Right="FullControl" />    <AppPermissionRequest Scope="http://sharepoint/content/sitecollection" Right="FullControl" />  </AppPermissionRequests> If I run the application, I got an access error. What do you mean exactly with that point "app must be deployed as a tenant scoped app by an administrator"? Thanks

  • Anonymous
    December 17, 2013
    Hi, Thanks for the article. I tried this using provider hosted app and got this error..any clue? "Your domain doesn't match the expected domain for this app deployment." Regards, Partha

  • Anonymous
    December 19, 2013
    how about /_api/contextinfo? if I need get the Form Digest Value, can I use the current contextinfo or I need to get it from "the other site"?

  • Anonymous
    January 08, 2014
    Garima, a tenant scoped app can have access to more than one site collection

  • Anonymous
    January 08, 2014
    Tudor, have you tried using WebProxy? msdn.microsoft.com/.../fp179895.aspx

  • Anonymous
    January 08, 2014
    Tolga, tenant scope != tenant level permissions (I know it can be confusing). The app must be installed by an admin as a tenant scoped app: msdn.microsoft.com/.../fp179896.aspx

  • Anonymous
    January 08, 2014
    Parthasaranthy, double check your domain matches your app. msdn.microsoft.com/.../jj687469(v=office.15).aspx  The error is telling you that the app domain isn't the one that is registered with SP.

  • Anonymous
    January 08, 2014
    Manuel, not sure exactly how/where you are using that info but my guess is that you can just query that from the appweb itself; no need for a cross-domain call.

  • Anonymous
    January 23, 2014
    Hi, Im getting following error message in safari browser when the app is launched modal dialog. The app works fine in full window mode. Blocked a frame with origin "https://763a65f1-26af-4fed-81c5-320da421cfc5.o365apps.net" from accessing a frame with origin "https://test-my.sharepoint.com". Protocols, domains, and ports must match. (x3). Is there anything i need to change in browser settings or can it be fixed in code? Please help

  • Anonymous
    February 01, 2014
    Could you elaborate how we can use REST and JSOM in provider hosted app where we are using server to server authentication.

  • Anonymous
    February 04, 2014
    Hi, Is it possible to get the cross site collection in sharepoint hosted app using sharepoint Client Object Model. we are using the sharepoint 2013 online. ClientContext sourceClientContext = TokenHelper.GetClientContextWithAccessToken(currentWebURL, appOnlyAccessToken);                if (sourceClientContext != null)                {                    Web objSite = sourceClientContext.Web;                    sourceClientContext.Load(objSite);                    sourceClientContext.Load(objSite, w => w.Title, w => w.Url, w => w.AssociatedOwnerGroup);                    sourceClientContext.ExecuteQuery(); } But unable to use  AppContextSite. Please Help

  • Anonymous
    February 05, 2014
    Karman, The cross-domain library is designed to be used with JavaScript. If you're using the .NET client object model you should probably use OAuth instead of the cross-domain library. Check msdn.microsoft.com/.../fp179897.aspx

  • Anonymous
    April 24, 2014
    I am creating a web site that leverages sharepoint apis. I am running into issues with 401 errors unless I do a NTLM auth in Javascript. How do I avoid having to auth every time. Is there a way to get a cookie

  • Anonymous
    May 08, 2014
    Why the "remote hosted" chose AppWebProxy.aspx from the "app web" not from the "Host web" directly, since the "iframing" can surpass clients calls through different domains ?Why use of the "app web" as an intermediary?

  • Anonymous
    May 20, 2014
    Hi, thanks for the information,  I have  query, please help I have app web hosted in my local system and my app got deployed in Server 1( SharePoint server). I have created a user in Server, when I am logging with new user in my local machine, app is not accessible and throwing an error "The remote server returned an error: (401) Unauthorized." permissions given to server 1 admin but not able to give for the new user created. identification :

  1. Domain names both are different ( local system domain is different from the server 1) please help in this
  • Anonymous
    May 20, 2014
    sorry to mention the permission given in my local hosted application, as it hightrust provider hosted app

  • Anonymous
    June 24, 2014
    Thank you so much. It was really helpful. I am trying to connect to the My Sites of current user. Your article was great.

  • Anonymous
    August 21, 2014
    Humberto, This is quite a good article but Ithink I don´t get it through. I have a two views MVC site right now as a provider hosted App. A few days ago I have a direct link from una view to another and it worked good. Nos I added some code retrieving information from SP context before making the call to the other view. And I got a message that the content can not be displayed in the iframe. it Works if it is full screen. However I noticed that when the app is loaded there is a querystring variable that has the sharepoint host information, and it is lost once I click the link. Is this behavior somewhat related to this crossdomain? I´m gonna try any way, but I don´t know how to debug it, the seller dashboard is only for deployed apps, how can I be sure it is good before release? during debug? Thanks

  • Anonymous
    September 18, 2014
    Is cross domain data transfer possible using CSOM-javascript

  • Anonymous
    September 23, 2014
    Hi In my organisation we have different web applications for departments like HR, Finance, Billing, Support etc. There are many site collections inside every web applications. Now we have to create an Apps so we can show data from any web applications to any other web applications. Say i have Employee Leaves list on one of the site collection on HR web appln, now i want to show this list data on Finance or Billing sites. What type of apps i should use here? How to access data across web applications in apps?

  • Anonymous
    October 13, 2014
    Hi, We have two site collections, application site and my site. We need to access list items/library files like (.js/images) from application site in my site for branding it. Is any way to get list items, we tried listdata.svc/REST api - gives access denied error Note: we not developed SP app, just using js coding thanks in advance

  • Anonymous
    April 02, 2015
    Hi, I am trying to access the BCS list (created thorugh farm level external content type) residing in host web from sharepoint hosted app but not able to. Unauthorized error coming up. Please assist. I am using cross domain library with rest. Can we do this. and how. Please assist Thanks

  • Anonymous
    June 08, 2015
    The comment has been removed

  • Anonymous
    July 12, 2015
    Hi, Would you please help in my scenario? I want to host my SharePoint App (either SharePoint hosted or Provider Hosted) which access custom lists data from particular SharePoint site as abc.sharepoint.com/.../sitecollection Which approach I need to consider. Please Guide

  • Anonymous
    July 12, 2015
    Please consider this App is required to available at SharePoint Store 365 environment.