ms graph file upload to sharepoint site - microsoft-graph-api

For some strange reason, I cannot upload files or create folders in a drive using the MS Graph API. I can view/list and even delete without any issues. Same goes for personal OneDrive files...I can list and delete, but not upload or create folders. I can't even create an upload session. I have set up the API permissions correct as far as I can tell (due to the ability to list and delete), but something is amiss.
I'm using Ruby and its Net::HTTP class to make the HTTP requests, but I've tried with other languages as well, even the Github Javascript SDK (https://github.com/microsoftgraph/msgraph-sdk-javascript) and Java SDK (https://github.com/microsoftgraph/msgraph-sdk-java). Every attempt I make results in the same 400 (invalid request) error. My request looks like this:
PUT /v1.0/drives/b!0jlSfAMWs0mywYCiVQrxB8cBs6dbx0FDr8CYTNg4ITob3Q2lz0OER6Snzs1G_vHh/items/01L5VYWTF6Y2GOVW7725BZO354PWSELRRZ:/test.txt:/content HTTP/1.1
Accept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3
Accept: application/json
User-Agent: Ruby
Host: graph.microsoft.com
Authorization: Bearer <my auth code>
Content-Type: text/plain
Connection: close
Content-Length: 24
My test.txt file content
The error response back has no useful information for diagnosing my problem:
HTTP/1.1 400 Bad Request
Cache-Control: private
Content-Type: application/json
request-id: c42545c0-ee40-40f3-9c7d-19d0e69d8ac8
client-request-id: c42545c0-ee40-40f3-9c7d-19d0e69d8ac8
x-ms-ags-diagnostic: {"ServerInfo":{"DataCenter":"North Central US","Slice":"SliceC","Ring":"3","ScaleUnit":"003","RoleInstance":"AGSFE_IN_45"}}
Strict-Transport-Security: max-age=31536000
Date: Mon, 03 Aug 2020 16:23:47 GMT
Connection: close
Content-Length: 215
{
"error": {
"code": "invalidRequest",
"message": "Invalid request",
"innerError": {
"date": "2020-08-03T20:35:44",
"request-id": "c42545c0-ee40-40f3-9c7d-19d0e69d8ac8"
}
}
I've tried a few different paths for this PUT request to upload the file and get the same error in response:
sites/#{site_id}/drive/items/01L5VYWTF6Y2GOVW7725BZO354PWSELRRZ:/test.txt:/content
sites/#{site_id}/drive/root:/test.txt:/content
me/drive/items/01FF6DWVN6Y2GOVW7725BZO354PWSELRRZ:/test.txt:/content
me/drive/root:/test.txt:/content
My app registration has the following API permissions and I'm requesting each of these when making the OAuth access token request:
openid
email
profile
https://graph.microsoft.com/User.Read
https://graph.microsoft.com/Files.Read
https://graph.microsoft.com/Files.Read.All
https://graph.microsoft.com/Files.ReadWrite
https://graph.microsoft.com/Files.ReadWrite.All
https://graph.microsoft.com/Sites.Manage.All
https://graph.microsoft.com/Sites.Read.All
https://graph.microsoft.com/Sites.ReadWrite.All
Again - I get similar errors trying to create a folder in any drive or trying to create an upload session. These are both POST requests with a JSON body to a slightly different URL, but the end result is the exact same....a 400 error with absolutely no helpful information. Same thing happens at the 'beta' endpoint.
Microsoft won't help me unless I'm a "Unified Support or Premium customer". Every case I try to submit immediately is closed.
Anyone have any ideas?

Ok - an update to this. I ended up getting Microsoft O365 support involved and we did a Teams meeting where I screenshared and showed them the problem. They had me try a few things (including creating a brand new Sharepoint site) and the problem persisted. Needless to say, they were stumped themselves.
I then asked some colleagues to try to upload files to a Sharepoint site and it worked for them. Turns out, there was something strange wrong with my Azure app registration. I have no clue what it was because all its config was the exact same as my colleague's. So I ended up creating a brand new app registration and when I use that, everything started working.

Related

Google Home App, cannot get OAUTH working properly

We are building a smart home app using actions on google for the google home. Our app requires signing into our system to be able to access the users devices so they can control them using their voice over google home. Our user backend is built using AWS Cognito. We are using API.AI as part of the Google Home app.
I have configured the Cognito OAUTH2 endpoint and the actions on google app to work with each other using the auth code flow and varying scope's but there is something I am missing. When I attempt to link the user account to the Google Home app i get redirected to our login page. After filling out the user details I'm returned to the Google Home 'Discover' tab but there is a message across the bottom that states: ‘Bad response from IdP in Auth Code Exchange’.
I also have tried it using Google's OAUTH2 playground. It seems that when using that I am able to get the code from our OATUH server, but when trying to exchange the code for a token i get the following error:
HTTP/1.1 400 Bad Request
Strict-transport-security: max-age=31536000 ; includeSubDomains
X-content-type-options: nosniff
X-application-context: application:prod:8443
Transfer-encoding: chunked
Set-cookie: XSRF-TOKEN=35f58337-76f4-4993-a0c9-93429134ea42; Path=/; Secure; HttpOnly
Expires: 0
Server: Server
Connection: keep-alive
X-amz-request-id: 284d862e-b021-4079-b5f5-3cbce675983c
X-xss-protection: 1; mode=block
Pragma: no-cache
Cache-control: no-cache, no-store, max-age=0, must-revalidate
Date: Wed, 23 Aug 2017 13:51:42 GMT
X-frame-options: DENY
Content-type: application/json;charset=UTF-8
{
"error": "invalid_client"
}
I have checked and rechecked the client ID and client secret etc and cannot find any errors.
Does anyone have any idea how I might fix this problem?
Thanks in advance
ok,may be i know the reason.....If you use aws cognito ...
According to this doc (http://docs.aws.amazon.com/cognito/latest/developerguide/token-endpoint.html)
Authorization
If the client was issued a secret, the client must pass its client_id and client_secret in the authorization header through Basic HTTP authorization. The secret is Basic Base64Encode(client_id:client_secret).
they need put client and client sectet in header ...
Then I use aws http proxy caught the request of google progress .
Method request headers: {X-Cloud-Trace-Context=d7b6b9b8239965baf69acab659e80a01/13879251242019662389, CloudFront-Viewer-Country=US, CloudFront-Forwarded-Proto=https, CloudFront-Is-Tablet-Viewer=false, CloudFront-Is-Mobile-Viewer=false, User-Agent=google-oauth-playground AppEngine-Google; (+http://code.google.com/appengine; appid: s~oauth2playground), X-Forwarded-Proto=https, CloudFront-Is-SmartTV-Viewer=false, Host=en75z5h2rb.execute-api.us-east-1.amazonaws.com, Accept-Encoding=gzip, deflate, X-Forwarded-Port=443, X-Amzn-Trace-Id=Root=1-5a0fcef2-09197cd86a625ad47d78f0b7, Via=1.1 d63a8908759a2f4775b3f672ebf823cc.cloudfront.net (CloudFront), X-Amz-Cf-Id=nFdLK97vAS5HvmpNYkPpbUMOB4bCaM6pScHWTAReAnonLg1gXF7hSg==, X-Forwarded-For=107.178.195.199, 54.182.238.53, content-type=application/x-www-form-urlencoded, CloudFront-Is-Desktop-Viewer=true}
There are no Authorization in request header. So the Cognito will return back
"error": "invalid_client"
According this OAUTH2.0 spec (https://www.rfc-editor.org/rfc/rfc6749#section-2.3.1)
I have already ask AWS support. They said:
Thanks for contacting AWS Support and providing us with detailed references. I would be happy to assist with your question regarding Cognito supporting client credentials in the request-body.
After reading through the OAUTH2.0 Standards RFC 6749 [0], It looks like including the client credentials in the request-body is not recommended. Here's an excerpt on the spec:
"Including the client credentials in the request-body using the two parameters is not recommended and should be limited to clients unable to directly utilize the HTTP Basic authentication scheme (or other password-based HTTP authentication schemes)."

OAuth2 via Google/Google+ from ASP.NET MVC 5

I'm working on an MVC 5 app where I need to use oAuth2 from Google for authentication. There are quite a few tutorials out there (both typed and some video) that all show the same way of getting this setup but I simply cannot get them to work for me. So let me start from the beginning.
I started off using Rick Anderson's great blog post on how to get this setup. That blog post is a little bit dated so the steps are a little bit different when interacting with Google's site but aside from different navigation, all of the important information is in there and I was able to follow along. This led me to enabling the GooglePlus API and setting up the following Client ID to consume:
Fast forward to my code and I did the following things:
New MVC Application (Individual Accounts for Authentication)
Enabled HTTPS (using IISExpress for now but I trusted the certificate to keep browsers happy)
Configured my Startup.Auth.cs as such:
Startup.Auth.cs:
app.UseGoogleAuthentication(new GoogleOAuth2AuthenticationOptions()
{
ClientId = GoogleClientId,
ClientSecret = GoogleClientSecret
});
At this point, I was able to get the Google button to show up on the Login screen:
When I click it, it takes me to Google's authentication/authorization screen where I grant access for my application to access my Google account information.
Here I click "Allow" and, sadly, this is where things go wrong. But some things go right as well. At this point, if I look at my Connected Apps under my Google account, I do see now that my MVC application shows up. So Google's end of things seem good, for the most part. But when I inspect the requests, a red flag pops up:
In speaking with a few folks who are smarter than I am (thx Mr. Galloway!), it was suggested that I follow the advice of this blog post. So long story short, I made the following changes:
Configured my redirect URI for the Google API to be /signin-googleplus
Installed nuget package: Install-Package Owin.Security.GooglePlus
Modified my Startup.Auth.cs as such:
Startup.Auth.cs
app.UseGooglePlusAuthentication(new GooglePlusAuthenticationOptions
{
ClientId = GoogleClientId,
ClientSecret = GoogleClientSecret
});
And the result was the same:
In digging into this Access Denied error with Fiddler, I can tell that the response from the request to /signin-google is where the error=access_denied first comes up:
Digging into that 403, I see this response:
HTTP/1.1 403 Forbidden
Vary: X-Origin
Content-Type: application/json; charset=UTF-8
Date: Tue, 14 Jun 2016 23:36:15 GMT
Expires: Tue, 14 Jun 2016 23:36:15 GMT
Cache-Control: private, max-age=0
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
Server: GSE
Alternate-Protocol: 443:quic
Alt-Svc: quic=":443"; ma=2592000; v="34,33,32,31,30,29,28,27,26,25"
Accept-Ranges: none
Vary: Origin,Accept-Encoding
Content-Length: 213
{
"error": {
"errors": [
{
"domain": "usageLimits",
"reason": "userRateLimitExceeded",
"message": "User Rate Limit Exceeded"
}
],
"code": 403,
"message": "User Rate Limit Exceeded"
}
}
I have also tried these additional things just in case:
Multiple Google accounts (as a user, not owning the API account)
Incognito/InPrivate mode to ensure caches are cleared
Revoked application access to user accounts to try again
I really could use some help getting this redirect back from Google to work!
I started off using Rick Anderson's great blog post on how to get this setup.
It's working for me well (it's good solution in my opinion), and problem probably is in other place - read below.
In speaking with a few folks who are smarter than I am (thx Mr. Galloway!), it was suggested that I follow the advice of this blog post. So long story short, I made the following changes
Never use this, so can't confirm if it's working.
In digging into this Access Denied error with Fiddler,
User Rate Limit Exceeded
Looks like you exceed limit on your Google Account - please, read more about this here:
Using OAuth 2.0 to Access Google APIs (especially Token expiration section)
User Rate Limit Exceeded for Google Cloud Storage OAuth2 API

OAuth 2.0 Access Token Request using Google OAuth Playground

I'm trying to exchange an OAuth 2.0 Authorization Code for an Access Token using Google's OAuth Playground tool. So, I get to step 2 and there it shows the HTTP POST request it will be sending out to MY_SERVER (I obfuscated the exact IP address for security reasons).
To me this looks correct and if I use a POST tool with exactly this request, it does arrive on my server. Launching it from the Playground, it doesn't arrive on my web server (nothing in the logs).
Does anybody have an idea what might be going wrong?
THIS POST
POST /tb/html/token/ HTTP/1.1
Host: MY_SERVER.COM
Content-length: 170
content-type: application/x-www-form-urlencoded
user-agent: google-oauth-playground
code=Splxl0576dGF6567gFG&redirect_uri=https%3A%2F%2Fdevelopers.google.com%2Foauthplayground&client_id=jarne&scope=&client_secret=some_secret&grant_type=authorization_code
RESULTS IN
HTTP/1.1 400 Bad Request
Content-length: 105
Content-type: text/plain
An error occured while connecting to the server: Unable to fetch URL: http://MY_SERVER.COM/tb/html/token/

403 Error with WiFi Hotspots

I have an iOS app that connects to a Django server via XMLRPC (the protocol doesn't really matter). Authentication is persisted with standard cookies and is transparently handled by AFNetworking via NSURLConnection. The Django XMLRPC library returns a 403 error when a request fails authentication, and when this happens the app displays a login page to the user. This approach has worked fine for a few years.
A recent problem came up with a user who connected to a WiFi hotspot but did not authenticate with the hotspot. They loaded the app and was shown the login page, which must have been the result of a 403 error coming back from the hotspot. If they first authenticate with the hotspot then everything works fine.
I'm trying to find a solution to prevent my app from interpreting such 403 errors as a failed authentication. I assume one of two things are happening:
the hotspot redirects to a URL that returns a 403 error; or
the hotspot immediately returns a 403 error.
The first scenario is easy to manage by blocking 301 and 302 redirects. Fortunately, AFNetworking makes this easy.
The second scenario is more difficult and I see no way of knowing from where the 403 originated.
Does anyone know if there is anything else in the header to detect the origin of a 403, or if there is a standard practice of redirecting the request when not signed into a hotspot?
Edit
Here are what my Django service header looks like on a 403:
HTTP/1.1 403 FORBIDDEN
Server: nginx
Date: Sun, 28 Apr 2013 07:21:34 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 0
Connection: keep-alive
Vary: Cookie
Set-Cookie: sessionid=5a5ce154d1229e40c3773e8f6999a32d; expires=Sun, 18-Aug-2013 07:21:34 GMT; httponly; Max-Age=9676800; Path=/
The simplest solution I could find was to add a custom header to the responses from my Django server, and validate the header in the client to assure it came from the server and not the hotspot.

YouTube API refresh token revoked with 400 code "invalid_grant" (for seemingly no reason)

This is my first post on stackoverflow. Here it goes.
I've built a server-side PHP application that involves reading/making changes to one users's YouTube account (changes to caption files). The user is authenticated with OAuth 2. I have been storing the refresh_token and making refresh requests successfully when the access_token expires.
But now, I seem to be getting an error, which coincidentally correlates with two things:
User's upload of a new video
Sunday nights
I don't know if that means anything.
The error happens when trying to refresh the access token and I'm using the same way of refreshing the token as I have previously. Here are the details:
Error message:
[status code] 400
[reason phrase] Bad Request
[url] https://accounts.google.com/o/oauth2/token
[request] POST /o/oauth2/token HTTP/1.1
Host: accounts.google.com
User-Agent: Guzzle/2.8.6 curl/7.24.0 PHP/5.3.10
Content-Type: application/x-www-form-urlencoded
client_id=442147492209.apps.googleusercontent.com&client_secret=D7eLQ5b0Mo1Y8uZ30ReWYwls&grant_type=refresh_token&refresh_token=1%2FCLvAt8V_d9sZznpg5YZdJlOJ58ufbHKL4F5Lw8PiJOg
[response] HTTP/1.1 400 Bad Request
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: Fri, 01 Jan 1990 00:00:00 GMT
Date: Tue, 02 Oct 2012 16:28:24 GMT
Content-Type: application/json
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
Server: GSE
Transfer-Encoding: chunked
{
"error" : "invalid_grant"
}
If you feel like looking at the source code, it's on github. Here's the relevant line number where refresh takes place: https://github.com/wellcaffeinated/yt-subtitle-explorer/blob/master/app/YTSE/OAuth/LoginManager.php#L330
(You'll notice that I've added a check for this error and ask the administrator to reauthorize the application... but this is far from ideal)
Other posts I've looked into were telling people to use approval_prompt=force... so I am doing that.
Edit:
My newest suspicion is that since I am requesting offline access (approval_prompt=force) every time the administrator logs in, I keep generating new refresh_tokens (which I don't record unless no others are available). Does google's OAuth have a maximum number of "active" refresh_tokens per application? Or something like that?
Thanks!
please check this from google developers pages:
If you receive an invalid_grant error response when attempting to use
a refresh token, the cause of the error may be due to the following
reasons:
Your server's clock is not in sync with NTP.
The refresh token limit
has been exceeded. Applications can request multiple refresh tokens to
access a single Google Analytics account. For example, this is useful
in situations where a user wants to install an application on multiple
machines and access the same Google Analytics account. In this case,
two refresh tokens are required, one for each installation. When the
number of refresh tokens exceeds the limit, older tokens become
invalid. If the application attempts to use an invalidated refresh
token, an invalid_grant error response is returned. The limit for each
unique pair of OAuth 2.0 client and Google Analytics account is 25
refresh tokens (note that this limit is subject to change). If the
application continues to request refresh tokens for the same
Client/Account pair, once the 26th token is issued, the 1st refresh
token that was previously issued will become invalid. The 27th
requested refresh token would invalidate the 2nd previously issued
token and so on.

Resources