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.
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.
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:
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 2013Anonymous
November 05, 2013
Parham, thank you, glad you liked the article :)Anonymous
November 26, 2013
Hi, the full URL Example link is not workingAnonymous
November 27, 2013
The comment has been removedAnonymous
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' 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"? ThanksAnonymous
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, ParthaAnonymous
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 collectionAnonymous
January 08, 2014
Tudor, have you tried using WebProxy? msdn.microsoft.com/.../fp179895.aspxAnonymous
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.aspxAnonymous
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 helpAnonymous
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 HelpAnonymous
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.aspxAnonymous
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 cookieAnonymous
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 :
- 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 appAnonymous
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? ThanksAnonymous
September 18, 2014
Is cross domain data transfer possible using CSOM-javascriptAnonymous
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 advanceAnonymous
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 ThanksAnonymous
June 08, 2015
The comment has been removedAnonymous
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 GuideAnonymous
July 12, 2015
Please consider this App is required to available at SharePoint Store 365 environment.