Use sharepoint cross-domain javascript library to consume REST API from localhost - web-services

I try to consume the sharepoint rest API from an application deployed in localhost. The sharepoint site is hosted in Sharepoint 2013 online.
For that purpose I use the javascrpt cross domain library. I get an example here https://github.com/OfficeDev/SharePoint-Add-in-REST-OData-CrossDomain.
My application is a full static website and I don't have VS, so I tried to figure out the Add In authorization. I go to the _layouts/15/appinv.aspx page of my site to give the authorization of third party application:
app domain: localhost:8080
redirect url: http://localhost:8080 (pointless?)
permission request XML: <AppPrincipal><RemoteWebApplication ClientId="*" /></AppPrincipal>
When I go to my application, I'm authenticated with my account: the cookie is populated with the token in FedAuth and rtFa
I'm supposing that it should be enough to now consume the API:
var executor = new SP.RequestExecutor(addinweburl);
executor.executeAsync(
{
url:
addinweburl + "/_api/web/GetFolderByServerRelativeUrl('Shared%20Documents')"
,
method: "GET",
headers: { "Accept": "application/json; odata=verbose" },
success: function(e) {
alert('success');
},
error: function(e, c, d) {
alert('fail');
}
}
);
The error handler is called and the 1007 error code is sent. This is quite weird since this code is used when size is too important.
Any help is appreciated.

The library can't be used if the application is not deployed on the same sharepoint site domain...
I fallback to OAuth protocol in order to authenticate my client.
The following documentation was key to understand how to obtain an access token: https://github.com/wearearchitect/sharepoint-oauth-app-client/blob/master/docs/Credentials.md

Related

How to troubleshoot zoom Oauth2 integration with ngrok and cookie usage in a MERN stack application?

I'm testing a local zoom app build. To be specific, zoom docs differentiate their app types, and what i want is a web view opened in the zoom client app view, therefore what ive developed is technically referred to as a "Zoom App" (more info here)
In the zoom docs, it mentions you cant setup the redirect urls to be localhost:8080 for example, it has to be set up with ngrok or a public url (more info here)
So ngrok is properly working (setup with cli command ngrok http 8080 ). I also tried this command with other values set for the --host-header flag. some attempts include --host=header=rewrite, --host-header=localhost, and --host-header=localhost:8080
Express server on :8080, react client on :3000
Express is linked into multiple oauth providers, google and zoom are 2 examples. google integration is working properly with the same oauth middleware, and route controllers on the api side (but google integration doesnt require the ngrok setup)
with zoom, and the ngrok setup, the request to the /callback route once the user confirms the zoom authorization, everything works fine, except the cookie that is returned by the server setting the header set-cookie is not set into the browsers application storage. nothing is registered in the cookies tab for oauth that goes through ngrok
the very next request confirms no cookie is stored, as there is no cookie: ... header in the request. interestingly, there are no errors on this cookie that is sent in the initial response headers of the servers /callback endpoint
Oauth Requests through Ngrok:
Oauth Requests without Ngrok:
Heres the controller that run after successful oauth verification/tokenization, triggered in both cases:
const oauth = catchAsync(async (req, res) => {
const user = req.user;
const tokens = await tokenService.generateAuthTokens(user);
res
.cookie('refreshToken', tokens.refresh.token, {
maxAge: tokens.refresh.maxAge,
httpOnly: true,
sameSite: "none",
secure: true,
// domain: "8796-2603-6011-223-7a04-2830-4c71-6f20-54c0.ngrok.io" // test
})
.redirect(`${config.clientURL}/app`)
});
I tried manually setting the domain value of the cookie config. Some values i tried include
localhost
localhost:8080
some-ngrok.io
, but to no avail
Heres the devserver webpack config, which usually has nothing extra, although i did also try with all for allowedHosts
But Im hopeful for a solution that works in both production and development
module.exports = {
// Extend/override the dev server configuration used by CRA
// See: https://github.com/timarney/react-app-rewired#extended-configuration-options
devServer: function (configFunction) {
return function (proxy, allowedHost) {
const config = configFunction(proxy, allowedHost);
// config.headers = {
// // "Cross-Origin-Embedder-Policy": "credentialless",
// // "Cross-Origin-Opener-Policy": "same-origin",
// // 'Cross-Origin-Resource-Policy': 'cross-origin',
// // 'Access-Control-Allow-Origin': '*'
// };
config.allowedHosts = ['all']
return config;
};
},
};
So maybe this is just a development environment issue? After all, google oauth works fine in prod/dev, maybe its just ngrok. So i've tested this by adding my live api url to the oauth redirect/allowedhost in zoom app web portal and ran this in production, and got the same issue.
Any one else go through this with a zoom app?

.NET Core 3.1 CORS not working on Ember (3.12) web UI

I am migrating a .NET Core Web API from 2.2 to 3.1. I have followed the Microsoft migration instructions and placed the call to the CORS middleware between UseRouting and UseEnpoints. However, I am still getting CORS errors.
In the ConfigureServices method, I have:
services.AddCors();
In the Configure method, I have:
app.UseRouting();
app.UseCors(options => options
.AllowAnyOrigin()
.AllowAnyHeader().AllowAnyMethod()
);
app.UseAuthentication();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
The console error in the web browser is:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading
the remote resource at http://localhost:5000/users/login. (Reason:
CORS header ‘Access-Control-Allow-Origin’ missing).
Cross-Origin Request Blocked: The Same Origin Policy disallows reading
the remote resource at http://localhost:5000/users/login. (Reason:
CORS request did not succeed).
Diagnostics:
I tried following Microsoft's documentation Enable Cross-Origin Requests (CORS) in ASP.NET Core, but it uses outdated references, such as; UseMvc and IHostingEnvironment.
I tried creating a brand new Web API and Ember Web-UI, but that did not work either. You can find a simple example getting-started-with-ember-js-and-net-core-3
Any idea what is causing the problem?
The ideal bounty reward will go to the answer that works. Preferably, a working bare-bones project will be posted on Git.
Note: I am allowing any origin right now just so I can get it to work. Ultimately, this will need to work with a Web-UI that is on http://localhost:4200
Update
The status code received is HTTP 405 - method not allowed. The method in question is an OPTIONS method.
The .NET Core 2.2 to 3.0 migration document is incorrect. The call to UseCors(); needs to be placed before the UseRouting() function. I went ahead and added it before the UseHttpsRedirection() as I saw that in an implementation on another site.
https://learn.microsoft.com/en-us/aspnet/core/migration/22-to-30?view=aspnetcore-3.1&tabs=visual-studio#migrate-startupconfigure
In ConfigureServices
services.AddCors(options =>
{
options.AddPolicy("CorsApiPolicy",
builder =>
{
builder.WithOrigins("http://localhost:4200")
.WithHeaders(new[] { "authorization", "content-type", "accept" })
.WithMethods(new[] { "GET", "POST", "PUT", "DELETE", "OPTIONS" })
;
});
});
In Configure
app.UseCors("CorsApiPolicy");
//app.UseHttpsRedirection();
app.UseJsonApi();
app.UseRouting();
app.UseAuthentication();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});

On what domain is my Javascript in my Office Add-In

We have an Outlook Add-In which runs in OWA.
The Manifest sits on https://company.ourdomain.com
The Javascript sits on https://company.ourdomain.com
The Custom Web Service we wrote in-house sits on https://company.ourdomain.com
When I make a call from within JavaScript in response to an Add-In Command, I use the format https://company.ourdomain.com/api/Controller/Action in the ajax call.
I end up getting one of those CORS errors (sometimes it's pre-flight, other times CORB). Why am I getting this if the Javascript is literally sitting on the same domain as the web service?
I'm assuming I'm authenticated since I've logged into my Outlook account.
What gives?
NOTE:
As an experiment I attempted a RESTful call by directly typing in the URL (No OWA involved). This caused the code to Authenticate against Azure AD. Then afterward I logged into OWA in the same browser session and everything worked fine. Do I actually need to authenticate within the Javascript even if the webservice I'm calling is in the same domain?
AJAX CALL WHICH GENERATES ERROR
Remember, it will work just fine after I've made a RESTful call by making a call to my web service directly from the Browser
var apiUri = '/api/People/ShowRecord';
$.ajax({
url: apiUri,
type: 'POST',
data: JSON.stringify(serviceRequest),
contentType: 'application/json; charset=utf-8',
dataType: 'json'
}).done(function (response) {
if (!response.isError) {
// response to successful call
}
else {
// ...
}
}).fail(function (status) {
// some other response
}).always(function () {
console.log("Completed");
});
OBSERVATION
When I call the api from the Address Bar the code below is run. This code never gets invoked by Javascript
[assembly: OwinStartup(typeof(EEWService.AuthStartup))]
namespace EEWService
{
public partial class AuthStartup
{
public void Configuration(IAppBuilder app)
{ app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseWsFederationAuthentication(
new WsFederationAuthenticationOptions
{
Notifications = new WsFederationAuthenticationNotifications
{
RedirectToIdentityProvider = (context) =>
{
context.ProtocolMessage.Whr = "ourdomain.com";
return Task.FromResult(0);
}
},
MetadataAddress = ConfigurationManager.AppSettings["ida:MetadataAddress"],
Wtrealm = ConfigurationManager.AppSettings["ida:Audience"],
TokenValidationParameters = new TokenValidationParameters
{
ValidAudiences = new string[] { $"spn:{ConfigurationManager.AppSettings["ida:Audience"]}" }
}
});
app.UseWindowsAzureActiveDirectoryBearerAuthentication(
new WindowsAzureActiveDirectoryBearerAuthenticationOptions
{
Tenant = ConfigurationManager.AppSettings["ida:Tenant"],
TokenValidationParameters = new TokenValidationParameters
{
ValidAudience = ConfigurationManager.AppSettings["ida:Audience"]
},
MetadataAddress = ConfigurationManager.AppSettings["ida:MetadataAddress"],
});
}
}
}
There are a few problems with this I think.
The first one is you are trying to serve your static content off the same server you are serving your code from. This is in general considered a bad-practice, purely because no point in wasting those precious server resources for static content. Ideally you should upload your static content to a CDN - and let the users' browser make a request to some super-cached file server. However - I understand this option might not be available to you as of now. This also isn't the root cause.
The second and the real problem is, (you think you are but) you are not authenticated. Authentication in Outlook web-addins doesn't come by default, it's something you need to handle. When Outlook loads your web add-in into the side panel it makes certain methods available to you which you can use and kind-of create a pseudo-identity (as an example Office.context.mailbox.userProfile.emailAddress ) - but if you want real authentication, you will need to do that yourself.
There are three ways of doing that as far as I can tell.
The first one is through the Exchange Identity Token
Second one is through the Single Sign On feature
The third one - which I think is the most convenient and the simplest in logic to implement is using WebSockets. (SignalR might be what you need).
When the user loads your first page, make sure a JS value like window.Unique_ID available to them. This will come in handy.
Have a button in your UI - which reads "Authenticate"
When the user clicks to this button, you pop them out to a url which will redirect to your authentication URL. (Something like https://company.ourdomain.com/redirToAuth). This would save you the trouble of getting blocked in the side-panel, because you are using window.open with a url that's on your domain. Pass that Unique_ID to redirection which then redirects you to OAuth login URL. That should look like https://login.microsoftonline.com/......&state=Unique_ID
Right after popping the user to sign in window, in your main JS (which is client-side), you open a web-socket to your server, again with that Unique_ID and start listening.
When the user completes authentication, the OAuth flow should post back either an access token, or the code. If you get the access token, you can send it through the sockets to front-end (using the Unique_ID which is in the parameters of post-back) or if you had the code, you finish authenticating the user with a server-to-server call and pass the access token the same way afterwards. So you use that unique Id to track the socket that user connected from and relay access token to only that user.

Ionic app not issuing POST request

I have an interesting problem with my Ionic application with a Django API server backend.
In previous versions of my app (0.0.1-.0.0.5) this hasn't come up, but starting now I'm not able to issue a POST request to get my authentication token.
Using Ionic locally ionic serve against my deployed server, when I attempt a login, my server registers an OPTIONS /token-auth/ and then POST /token-auth/. When I run the application on my device ionic run android and attempt to login the server only registers the OPTIONS request but does not register the POST, according to the server logs.
I've found out this is due to CORS, it issues an OPTIONS first to see what it is allowed to issue. For some reason the OPTIONS request comes back with absolutely nothing. In my other Django Rest Framework projects, the OPTIONS comes back with a proper response. I think this is related, but it's strange that it works from localhost to the deployed server with the OPTIONS request responding the same.
My login function is pretty basic:
$http({
method: 'POST',
url: config.apiUrl + 'token-auth/',
data: {
"username": usernameElement[0].value,
"password": passwordElement[0].value
}
}).then(function(data) {
console.log('success', data);
...
}, function(err) {
console.log('error', err);
...
});
Another thing I find interesting is that it runs the error function but instead of giving me back a normal error object in the err variable, I get back what appears to be the request object. I have never seen this before.
{
"data":null,
"status":0,
"config":{
"method":"POST","transformRequest":[null],
"transformResponse":[null],
"url":"http://example.com/api/token-auth/",
"data":{
"username":"myuser",
"password":"mypassword"
},
"headers":{
"Accept":"application/json, text/plain, */*",
"Content-Type":"application/json;charset=utf-8"}
},
"statusText":""
}
Runs fine local app to deployed server
Device app to deployed server doesn't register POST request, only OPTIONS
AJAX error return is the request object, not the error response object
I've been stuck on this for a couple days now and am looking for any ideas.
This was in fact a CORS problem. After debugging through django-cors-headers I found that it was not passing the CORS. I later found out that instead of serving on http://192.168.1.36:8100 for some reason ionic switched to serve on http://192.168.1.10:8100

calling web service using jquery

I'm trying to call a local webservice/webApi using jquery, but I have been stuck for days. could somebody help me please.
So my webservice is sitting on localhost port 4011 i.e. localhost:4011/api/poi/
And my javascript is sitting on local host port localhost:4213/ and here is how I call it:
$.get('http://localhost:4011/api/values', function (data) {
alert(data);
});
When I enter the url into the browser directly, it returned the result. But when I'm calling it using the jquery. I have no response (by looking from the developer tools).
I'm not sure what I'm doing wrong. Please help.
I'm using webApi mvc .net4 if that helps.
This is due to the Same origin policy. Because the API is on a different port to where you're serving the web page the browser will not allow you to make the request.
You can use jsonp to get around this, or by using cross origin policy on your web service.
Use this if you are using a CrossDomain as CrossDomain doesn't work in jQuery!
$.ajax({
url: 'ajax/test.html',
crossDomain: true,
success: function(data) {
alert(data);
}
});
you might be restricted by the cross origin policy CORS. Configure your web service to accept the requests made from across the domain. You can add Access-Control-Allow-Origin headers like
responseMessage.Headers.Add("Access-Control-Allow-Origin","*");