Please specify what version of the library you are using: [1.2.6]
Please specify what version(s) of SharePoint you are targeting: [ SharePoint 2013 On-prem ]
Trying to request web on different web application.
I enabled cross domain restricted on specific domain via web.config.
I get an Http 401 with pnp because of CORS preflight check which is normal.
But i'm able to bypass it by using withCredentials property on jquery ajax request:
jQuery.ajax({
url: 'http://myspsite/_api/web',
type: 'GET',
dataType: 'json',
xhrFields: { withCredentials: true },
success: function (data)
{
},
error: function ajaxError(response) {
console.log(response.status + ' ' + response.statusText);
}
});
Is there a way to do it with pnp or an other way ?
Thank you.
Hi @NicolasR,
PnPjs is based on fetch. There is a configure method where custom config can be passed to the client.
Something similar to this should do the thing:
const web = new Web('[ABSOLUTE_URL]');
web
.configure({
mode: 'cors',
credentials: 'include'
})
.select('Title')
.get().then(console.log);
Hi @koltyakov,
Thank you for the information.
So I tried what you provide for pnp configure, I always get the same error as before:
Access to XMLHttpRequest at 'http://myspsite/_api/web?$select=Title' from origin 'http://myorigin' has been blocked by CORS policy:
Response to preflight request doesn''t pass access control check: It does not have HTTP ok status.
Now I tried with fetch and it works:
fetch('http://myspsite/_api/web',{
credentials: 'include'
})
Maybe is there a missing parameter ?
Maybe you should not provide mode: 'cors', in configure as well as in a raw fetch request as far as it works?
I forgot to say that I tried to remove mode: 'cors'.
So I analyzed request with fiddler. When using pnp with configure and credentials: 'include', NTLM authorization header is missing.
I believe the browser behavior is to strip the authorization header for cors requests unless explicitly allowed by the server being called.
I allowed request on destination server by modifying web.config.
Requests work when using jQuery Ajax or fetch but doesn't with pnp.
Authorization header is present with jQuery or fetch but not with pnp. Is it a normal behavior ? If yes, I will do my request with jQuery but @koltyakov mentionned that pnpjs is based on fetch so ?
I didn't have yet a chance to look closely at this but assume that probably credentials: 'include' ends up not being passed to the final request. The fact that manually crafted with raw fetch request works means that it is feasible to do the same within PnPjs.
I was managed to dig a bit deeper with this. It's not credentials: 'include' issue, but a CORS specifics related to the headers.
PnPjs adds default value of application/json;odata=verbose;charset=utf-8 for Content-Type (CORS supports only application/x-www-form-urlencoded, multipart/form-data, text/plain), as well as the following headers: X-ClientService-ClientTag, User-Agent and X-RequestDigest (required for some POST requests to the API).
Fetch begins to fail with CORS when CORS restrictions are violated:
fetch(`${spOnAnotherDomainURL}/_api/web?$select=Title`, {
credentials: 'include',
headers: {
Accept: 'application/json;odata=verbose',
// 'Content-Type': 'application/json', // will fail if provided
// 'X-ClientService-ClientTag': 'PnPCoreJS', // will fail if provided
}
})
.then(r => r.json())
.then(console.log)
.catch(console.log)
CORS settings in IIS should allow specific request headers and methods:
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="http://my-external-app-domain.com" />
<add name="Access-Control-Allow-Credentials" value="true" />
<add name="Access-Control-Request-Headers" value="User-Agent,Content-Type,Authorization,X-RequestDigest,X-ClientService-ClientTag" />
<add name="Access-Control-Request-Method" value="GET,POST,HEAD,OPTIONS" />
</customHeaders>
</httpProtocol>
However, not sure that custom X-* (e.g. X-ClientService-ClientTag) headers can even be configured, at least this never worked for me.
Also, with CORS, anything a bit more complex than a simple get request won't work due to the Content-Type limitations. So, for instance, you can't add an item even in theory.
Besides that, every time I hear someone tries consuming SharePoint API this way (On-Prem & CORS) it happens that some problem is being tried to be solved in the wrong way. If it a production solution it's better considering a web service dealing with requests server-side. If it's a dev toolchain situation something like rest proxy is a solution. But not the CORS.
@NicolasR can you elaborate your use case?
Hello,
Thanks for your investigation.
My use case is the following: I need to get some informations on a web site on an other web application on the same server.
It's the first time I need to do this client side. I want to avoid to create a specific web service for this purpose if possible.
While it's only displaying data the assumption is that the data should not be complex and probably end up with a few types of requests, hopefully, GET only. I'd suggest raw REST & fetch /w CORS with a fallback plan to a web service or data synchronization.
Let's wait for others' opinions.
Ok I think we can close this.
Thank you for your time.
I nearly pulled my hear out over this and found no solution as well.
On a SharePoint 2013 Server with configured CORS header generation I got it down to:
Don't know why this fails. Beware.