I'm successfully using the Graph API for a variety of things but I need to access to the OneNote API to perform student and teacher add/remove operations on Class Notebooks. When I request a token the same way that I do for Graph with the https://www.onenote.com resource it provides one but when I try to use it to access the OneNote API no matter what (valid) request I send I get 401 - "The request does not contain a valid authentication token."
I've tried using the v1.0 endpoint to generate a token instead with the same results.
My token requests:
POST https://login.microsoftonline.com/{my tenant}/oauth2/v2.0/token HTTP/1.1
Accept: application/json
Content-Type: application/x-www-form-urlencoded
Host: login.microsoftonline.com
Content-Length: 213
Expect: 100-continue
Connection: Keep-Alive
grant_type=client_credentials&client_id={my appid}&client_secret={my secret}&tenant={my tenant}&scope=https%3A%2F%2Fwww.onenote.com%2F.default
OR
POST https://login.microsoftonline.com/{my tenant}/oauth2/token HTTP/1.1
Accept: application/json
Content-Type: application/x-www-form-urlencoded
Host: login.microsoftonline.com
Content-Length: 161
Expect: 100-continue
grant_type=client_credentials&client_id={my appid}&client_secret={my secret}&resource=https%3A%2F%2Fwww.onenote.com
Both return something containing an access_token, like:
{"token_type":"Bearer","expires_in":"3600","ext_expires_in":"3600","expires_on":"1543513719","not_before":"1543509819","resource":"https://www.onenote.com","access_token":"{a token}"}
Request:
GET https://www.onenote.com/api/v1.0/myorganization/groups/{group id}/notes/ HTTP/1.1
ContentType: application/json
Authorization: Bearer {token returned from /token request}
Cache-Control: no-store, no-cache
Host: www.onenote.com
Response:
code=40001
message=The request does not contain a valid authentication token.
For reference, this question is basically a follow-up to: Adding Students with the API and Class Notebook
You're on the right track.
Resource is the right way with the 1.0 auth endpoint.
Scopes need to be registered on the app portal, so you'll need to go back in and add OneNote scopes in the portal.
I'm not 100% sure, but IIRC the resource for onenote might require a trailing '/'.
Related
From postman I'm trying to post a file to an asp.net core 2.2 api-controller.
POST /api/epd/noshow/uploadfile HTTP/1.1
Host: localhost:44361
User-Agent: PostmanRuntime/7.11.0
Accept: */*
Cache-Control: no-cache
Postman-Token: 3d633228-2554-442b-84f4-4e8214972886,a8f994f4-973e-411f-b96b-778af2c082b4
Host: localhost:44361
accept-encoding: gzip, deflate
content-type: multipart/form-data; boundary=--------------------------201375848683546790642901
content-length: 237
Connection: keep-alive
cache-control: no-cache
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="file"; filename="C:\temp\caldr.json
------WebKitFormBoundary7MA4YWxkTrZu0gW--
The api-controller method
[HttpPost]
[AllowAnonymous]
public IActionResult UploadFile([FromForm]IFormFile file)
{
return Ok();
}
I've already tried FromForm, FromBody, nothing. Setting content-type in postman, not setting the content-type in postman always returns the same error.
Any suggestions ?
That is simple than expected :) You to send the request body in a form data. Here, this example shows only the simple file post call with ASp.NET Core 2.2 - WebAapi
Postman:
API:
Found the problem and solution. Just for reference if someone else encounters the same mind boggling problem.
On the 'grandmother' class of the controller, there is the following attribute :
[Consumes("application/json")]
of course form-data was not accepted :-)
override this default behaviour by adding the following attribute to the action
[Consumes("multipart/form-data")]
I am trying to create a hybrid connection in Azure BizTalk service using rest API. Nevertheless, I am receiving this error:
<Error xmlns="http://schemas.microsoft.com/windowsazure" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Code>InternalError</Code>
<Message>The server encountered an internal error. Please retry the request.</Message>
</Error>
Request:
PUT https://management.core.windows.net/36be0e4b-0a10-4b12-8b1c-6aefd3df3fe9/cloudservices/Default-BizTalk-South-Central-US/resources/biztalkservices/~/biztalk/qwbiztalkservice/hybridconnection/namenewhybridconnection HTTP/1.1
Accept: application/xml
x-ms-version: 2012-08-01
Content-Type: application/xml; charset=utf-8
Host: management.core.windows.net
Content-Length: 152
Expect: 100-continue
Connection: Keep-Alive
<HybridConnectionInput xmlns=\"http://schemas.microsoft.com/windowsazure\">
<HostName>myhost</HostName>
<Port>443</Port>
</HybridConnectionInput>
Documentation reference: https://msdn.microsoft.com/en-us/library/azure/dn743828.aspx
I have code that works, but I'm having a difficult time making the connection as to why it works.
I have code in an AngularJS factory function that makes this call:
$http.get('http://webServerName/PrestoWebApi/api/apps/')
And this is the Web API controller (C#):
[EnableCors(origins: "http://webServerName", headers: "*", methods: "*")]
public class AppsController : ApiController
The source of the call would be a user's computer, for example, a laptop with the name JoesLaptop. And that laptop could run anywhere. (Currently, this is all running inside one LAN, but the user could be anywhere.)
So why does specifying the web server name within the EnableCors attribute work? Isn't the request coming from the browser on Joe's laptop and not from the web server itself?
Edit
If I remove the EnableCors attribute, I get this error in the F12 tools in the browser:
XMLHttpRequest cannot load http://webServerName/PrestoWebApi/api/apps/. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://webServerName' is therefore not allowed access.
Edit 2
Request:
GET http://fs-6103.fs.local/PrestoWebApi/api/apps/ HTTP/1.1
Host: fs-6103.fs.local
Connection: keep-alive
Accept: application/json, text/plain, */*
Origin: http://fs-6103
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.111 Safari/537.36
Referer: http://fs-6103/PrestoWebApi/app/
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Response:
HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/7.5
Access-Control-Allow-Origin: http://fs-6103
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Fri, 31 Oct 2014 18:30:05 GMT
Content-Length: 2931171
If webServerName is rendering an HTML page that is starting an asynchronous request to webServerName, then CORS doesn't apply and your server will serve that resource anyway.
I'm pretty sure that must be your case.
UPDATE
Based on the latest edits of the question and the comments that the OP has made bellow this answer, this is what must be happening.
The HTTP server that it's serving both the main HTML page and the API resource is the same, therefore there shouldn't be any need to EnableCORS. However, according to the headers of the Request the page is being served from http://fs-6103 and the $http.get is made to http://fs-6103.fs.local. That should explain everything.
UPDATE 2
Ok, I'm willing to bet that this is what's happening here:
The main page is being served by http://fs-6103
The $http.get is made towards: http://fs-6103.fs.local/
So far I'm not speculating, this is what the request is saying
The OP must have [EnableCors(origins: "http://fs-6103", headers: "*", methods: "*")] set into the API controller.
When this is disabled the OP is getting the error: No 'Access-Control-Allow-Origin' header is present on the requested resource, as it should be expected. And when the OP enables it everything works as expected.
Browsers/clients handle the security, and generally restrict things to single origin, meaning they only accept stuff from the server they made the request to. Enabling cors in the header (ACAO) or wherever lets that server tell the browser, "hey those other Cross origin resources are with me." The browser will generally go along with that.
It looks like ServiceStack only accepts session-based authentication. I was reading through https://github.com/ServiceStack/ServiceStack/wiki/Authentication-and-authorization and I couldn't find anything describing how to do what I want.
I also looked at http://enehana.nohea.com/general/customizing-iauthprovider-for-servicestack-net-step-by-step/ but that also is session-based.
What I would like to do, is very similar to how WebAPI works with Individual User Accounts.
I want to send this to the API:
POST http://localhost:49436/Token HTTP/1.1
User-Agent: Fiddler
Host: localhost:49436
Content-Type: application/x-www-form-urlencoded
Content-Length: 55
grant_type=password&username=Alice&password=password123
Then, if the user is found in my custom authentication method, it returns this:
{
"access_token":"boQtj0SCGz2GFGz[...]",
"token_type":"bearer",
"expires_in":1209599,
"userName":"Alice",
".issued":"Mon, 14 Oct 2013 06:53:32 GMT",
".expires":"Mon, 28 Oct 2013 06:53:32 GMT"
}
Then, the client app can just send the access_token on subsequent requests by appending a value like this to the HTTP request:
Authorization: Bearer boQtj0SCGz2GFGz[...]
Is this possible in ServiceStack?
Edit: Implementation using .NET's WebAPI: http://www.asp.net/web-api/overview/security/individual-accounts-in-web-api
I'm using RestSharp to build a Rest access to my MVC entry points (actually so I can use them from monotouch, but right now I'm testing on Windows 7, vs2010, .net 4, RestSharp 104.1)
if I create a request and call
client.ExecuteAsPost<Model.Client>( request );
it works, I can see in fiddler the raw packet
POST http://localhost.:49165/Services/Client/ClientAdminService/FindClient HTTP/1.1
Timestamp: Monday, March 18, 2013 1:56:02 AM
X-PS-Authentication: YADAYADA:<deleted for brevity>==
Accept: application/xml
User-Agent: RestSharp 104.1.0.0
Content-Type: application/xml; charset=utf-8
Host: localhost.:49165
Content-Length: 256
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
<Client xmlns="http://schemas.datacontract.org/2004/07/PSRMWebService.Model.Version1" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><ID>0</ID><MailingAddress i:nil="true"/><Mask>Name</Mask><Name>Rykercom</Name><PhysicalAddress i:nil="true"/></Client>
as you can see at the end is the serialized data blob I need to send to the server (of type Model.Client) this is added to the request using
Request.AddParameter("application/xml; charset=utf-8", DataPacket, RestSharp.ParameterType.RequestBody);
where DataPacket is the serialized blob created using a DataContractSerializer
Now if I change the code to call
Client.ExecuteAsyncPost<Model.Client>(Request, (response, handle) => { OnFindClientAsyncComplete(response, handle, Callback ); }, "POST");
Using Fiddler I get quite a different packet with no Body, no content type, and therefore a failed response from the server.
POST http://localhost.:49165/Services/Client/ClientAdminService/FindClient HTTP/1.1
Timestamp: Monday, March 18, 2013 2:35:08 AM
X-PS-Authentication: YADAYADA:<deleted for bevity>==
Accept: application/xml
User-Agent: RestSharp 104.1.0.0
Host: localhost.:49165
Content-Length: 0
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
the X-PS-Authentication is just a custom auth string. Anyone any ideas why the async call is leaving me with an empty message body ?
The simple answer is clone the current github repository for rest sharp and build it yourself. It appears the fix for executeasync is already in the tree.
Any chance who ever own the Nuget package can update it to the lastest sources ?
Thanks