Take the 2-minute tour ×
SharePoint Stack Exchange is a question and answer site for SharePoint enthusiasts. It's 100% free, no registration required.

I have a SharePoint 2013 SharePoint Hosted app, and I've got some code that works swimmingly well when it's pointed to the host site collection. Part of the requirement is to have it point to a user specified site collection. When I specify another site collection in my farm, it errors:

Access denied. You do not have permission to perform this action or access this resource

Is this possible? I'm guessing this is a security thing in the app model.

Update Adding some code, since it sounds like this should work. Also my app has Tenant Write permissions.

                var reqExecutor = new SP.RequestExecutor(appWebUrl);
                var url = appWebUrl + "/_api/SP.AppContextSite(@TargetSite)/web/lists/getByTitle(@TargetLibrary)/RootFolder/folders(@TargetFolderName)/files/" +
                        "add(url=@TargetFileName,overwrite='true')?" +
                        "@TargetSite='" + targetSiteUrl + "'&" +
                        "@TargetLibrary='" + targetLibrary + "'&" +
                        "@TargetFileName='" + fileName + "'&" +
                        "@TargetFolderName='" + folderName + "'";

                console.log('uploadDocToLibrary ' + url);
                reqExecutor.executeAsync({
                    url: url,
                    method: "POST",
                    headers: {
                        "Accept": "application/json; odata=verbose"
                    },
                    contentType: "application/json;odata=verbose",
                    binaryStringRequestBody: true,
                    body: fileData,
                    success: function (x, y, z) {
                        console.log("Successful upload, updating metadata");
                        getDocumentListItem(libraryName, fileName);
                    },
                    error: function (x, y, z) {
                        updateDivStatus('Error: ' + x.statusText);
                        console.log(x.body + " " + z);
                    }
                });

Another Update I switched from REST to CSOM, just to see, and I'm still getting access denied.

            function getTargetSiteName() {
                var context = new SP.ClientContext(appWebUrl);
                var hostContext = new SP.AppContextSite(context, targetSiteUrl);

                var web = hostContext.get_web();
                context.load(web);
                context.executeQueryAsync(
                    function () {
                        alert(web.get_title());
                    },
                    function (sender, args) {
                        alert(args.get_message());
                    });
            }

Update Appears to be a bug or a limitation with SharePoint Hosted apps... testing out a provider hosted instead.

share|improve this question
    
Have you tried granting Tenant permissions to the App? –  Brian P May 16 '13 at 15:41
    
I removed my previous comment, I added Tenant and it's still not working, getting same error. –  David Lozzi May 16 '13 at 16:59
add comment

4 Answers

Have you looked at the last part of this article from MSDN?

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 http://contoso.sharepoint.com/site1 wants to retrieve a list from http://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.

There is also a code example in the article

EDIT after code snippet added

How are you getting the reference to SP.RequestExecutor.js? Per the blog post above you should load it from the host web:

// 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.
    }
share|improve this answer
    
I am using the AppContextSite already, added code above –  David Lozzi May 16 '13 at 16:59
    
Sorry but I see no code –  Robert Lindgren May 16 '13 at 17:01
    
sorry, just added –  David Lozzi May 16 '13 at 17:02
    
Updated with more from the article, specifically an interesting part about how to load the SP.RequestExecutor :) –  Robert Lindgren May 16 '13 at 17:09
1  
Did you read the updated article where he states 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. –  Anders Rask Nov 5 '13 at 10:57
show 3 more comments

I think I had the same problem and here is the solution I found.

(and I think it is what Robert means, actually)

var hostweburl;
var appweburl;

var clientContext;
var appContextSite;
var web;

$(document).ready(function () {
    hostweburl = decodeURIComponent(getQueryStringParameter("SPHostUrl"));

    appweburl = decodeURIComponent(getQueryStringParameter("SPAppWebUrl"));

    $.getScript(hostweburl + "/_layouts/15/" + "SP.RequestExecutor.js", execCrossDomainRequest);
});

function execCrossDomainRequest() {
    clientContext = new SP.ClientContext(appweburl);

    appContextSite = new SP.AppContextSite(clientContext, 'http://the-collection-to-reach');

    web = appContextSite.get_web();

    clientContext.load(web);

    clientContext.executeQueryAsync(onRequestSucceeded, onRequestFailed);
}

function onRequestSucceeded() {
    alert(web.get_url());
}

function onRequestFailed(sender, args) {
    alert('Error: ' + args.get_message());
}

So far so good. It works.

I also had to grant my sharepoint-hosted app some rights (example):

<AppPermissionRequests>
  <AppPermissionRequest Scope="http://sharepoint/content/sitecollection/web" Right="FullControl" />
  <AppPermissionRequest Scope="http://sharepoint/content/sitecollection" Right="FullControl" />
  <AppPermissionRequest Scope="http://sharepoint/content/tenant" Right="FullControl" />
</AppPermissionRequests>
share|improve this answer
    
this code does not work for me. I still get access denied!. did you find any solution ? –  Pouyan Jan 29 at 11:46
add comment

If you've done everything right which is mentioned in the above steps. Try deploying your app through app catalogue to the target site. It will solve the problem.

share|improve this answer
add comment

This is not a bug and it's behavior by design. Apps can be deployed in 2 scopes:

1) Web Scope: Where you can only access data from the host web and the app web.

2) Tenant Scope: Where you can access data from any site collection in the Tenant provided you have the right permissions set in the AppManifest.

I believe your requirement calls for a Tenant Scoped App.

The scope is decided only by how you deploy your app. See these links for further details:

Tenancies and deployment scopes for apps for SharePoint

Batch Install SharePoint Apps in Tenant Scope

share|improve this answer
    
Thanks for your answer, and I agree, I do need Tenant Scope, but as I previously noted, I tried that and still received the error. I was working with MS closely on this project and their team had the same problem. Sadly, I have moved to another project and not sure if it is still an issue. –  David Lozzi Jan 29 at 19:09
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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