3

I am using JSOM to get the list contents of a list which is located in another site collection than my app. For example, my app is hosted here: portal.contoso.com/sites/myapp and the list is on top level: portal.contoso.com/myList.

I get an 403 Forbidden error if I try to access the list with JSOM. The app has Tenant-administrator permissions.

Here is my code:

var serverUrl: string = "https://portal.contoso.com/";

try {
    var clientContext: SP.ClientContext = new SP.ClientContext(serverUrl);
    var rootWeb = clientContext.get_web();

    clientContext.load(rootWeb);

    //Here it gets the SharePoint list e.g. portal.contoso.com/mylist
    var oList: SP.List = this.getAssetsList(clientContext);

    if (oList != null) {
        var camlQuery = new SP.CamlQuery();
        camlQuery.set_viewXml("<View><Query><Where><Geq><FieldRef Name=\'ID\'/>'" +
        "<Value Type=\'Number\'>1</Value></Geq></Where></Query><RowLimit>10</RowLimit></View>");
        this.sharePointCollectionListItems = oList.getItems(camlQuery);

        clientContext.load(this.sharePointCollectionListItems);

        clientContext.executeQueryAsync(
            Function.createDelegate(this, this.onQuerySucceeded),
            Function.createDelegate(this, this.onQueryFailed));
        }
    } catch (e) {
        console.log(e);
    }

How do I get this working?

  • It is the Javascript Object Model API does there exist something like SharePointOnlineCredentials? I only know it from C#. Do you have some code samples? – Philipp Eger Sep 17 '15 at 13:32
  • No there isn't, sorry :/ – Swayam Siddha Sep 17 '15 at 13:33
  • You may want to refer this article - dotnetcurry.com/sharepoint/1028/… Here the app context and the host context are both being used. – Swayam Siddha Sep 17 '15 at 13:37
6

To access information in the host web using the Javascript Object Model you need to use an SP.AppContextSite object in conjunction with your SP.ClientContext

I see you're using TypeScript, which is awesome, so I'll post my answer with both TypeScript and the working Javascript; my comments will have some additional information and you can paste the JS directly into your browser dev tools:

TypeScript

/// <reference path="microsoft.ajax.d.ts" />
/// <reference path="SharePoint.d.ts" />

var appweburl: string,
    hostweburl: string,
    context: SP.ClientContext,
    appContextSite:  SP.AppContextSite;

JSRequest.EnsureSetup(); // this is an easy method to retrieve URL parameters...
appweburl = decodeURIComponent(JSRequest.QueryString["SPAppWebUrl"]);
hostweburl = decodeURIComponent(JSRequest.QueryString["SPHostUrl"]);
// the context needs to be for the app web, so we can use get_current
context = SP.ClientContext.get_current();
// the appContextSite is for the hostweb,
// so we provide the hostweburl as the second parameter
appContextSite = new SP.AppContextSite(context, hostweburl);

// now we reference objects using the appContextSite
// but load and query using the context...
var list = appContextSite.get_web().get_lists().getByTitle("Site Assets");
var items = list.getItems(SP.CamlQuery.createAllItemsQuery());
context.load(items);

context.executeQueryAsync(function(sender, args) {
    // success
    console.log(items.get_count());
}, function(sender, args) {
    //failure
    console.log(args.get_message());
});

JavaScript (just excludes type annotations for those of who like to copy/paste and see some results!)

var appweburl, hostweburl, context, appContextSite;
JSRequest.EnsureSetup(); // this is an easy method to retrieve URL parameters...
appweburl = decodeURIComponent(JSRequest.QueryString["SPAppWebUrl"]);
hostweburl = decodeURIComponent(JSRequest.QueryString["SPHostUrl"]);
// the context needs to be for the app web, so we can use get_current
context = SP.ClientContext.get_current();
// the appContextSite is for the hostweb,
// so we provide the hostweburl as the second parameter
appContextSite = new SP.AppContextSite(context, hostweburl);
// now we reference objects using the appContextSite
// but load and query using the context...
var list = appContextSite.get_web().get_lists().getByTitle("Site Assets");
var items = list.getItems(SP.CamlQuery.createAllItemsQuery());
context.load(items);
context.executeQueryAsync(function (sender, args) {
    // success
    console.log(items.get_count());
}, function (sender, args) {
    //failure
    console.log(args.get_message());
});

You can find more information on this technique in the MSDN Article: Complete basic operations using JavaScript library code in SharePoint 2013, the host web stuff you're looking for is down at the bottom in the section titled "Access Objects in the Host Web".

Astute readers will notice that I do not initialize a SP.ProxyWebRequestExecutorFactory nor do I attach that factory to the context: while this methodology appears in most of the MSDN samples I've read, I have not found a single case where it is actually necessary. My guess (note the emphasis) is that you would need to use that pattern in the C# version of the Client Object Model, and since the Javascript Object Model is transpiled from the C# version the technique is likely carried over regardless.

  • Sorry, but the HostWeb variable contains only the url to the current site collection like "portal.contoso.com/sites/myappsite". But I need this: "portal.contoso.com" because the Assets library is stored on top level: "portal.contoso.com/assets". If I change the HostWeb variable to "portal.contoso.com" I get an "You have no permission" error. – Philipp Eger Sep 18 '15 at 7:32
  • @PhilippEger I'll do some testing later but I think you'll need to use the SP.RequestExecutor or a cross domain REST call to get data from a site above the one where the add-in is installed; more info here if you want to poke around on your own before I have time to take a look: msdn.microsoft.com/en-us/library/office/dn735924.aspx – John-M Sep 18 '15 at 12:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.