1

I am developing a rather simple application that retrieves files from SharePoint using the REST Office 365 API. This is a batch job running in the background with no user interface so the following simple 2-step flow is what I'm doing:

(1) Requesting an Access Token from Azure AD (supplying client ID, client secret, resource, and grant_type=client_credentials)

(2) Invoke the SharePoint API (https://{base url}/_api/v1.0/Files) using the "Authorization: Bearer " as a request header .

That process seems pretty straightforward and sounds simple but I keep getting the following error:

401 Unauthorized

x-ms-diagnostics:  3001000;reason="There has been an error authenticating the request.";category="invalid_client"

Any idea what the problem is and how this can be resolved ? I have been stuck on this for days now. I would REALLY appreciate somebody's help with this. Thanks.

MrPiao
  • 688
  • 5
  • 19
CDub
  • 11
  • 1
  • 2

2 Answers2

3

SharePoint Online doesn't yet support clients accessing it using app-only tokens (resulting from client credential OAuth2 flow). It only supports delegated token aka user+app tokens (resulting from authorization code OAuth2 flow).

So, if you wish to write a client application (web app or native client app) that accesses SharePoint online - it can only be on behalf of a user, and it must involve interactive authentication of the user - after the user authenticates - they will be shown a consent page where they need to consent to your application accessing the O365 API on their behalf.

Only Mail/Calendar/Contacts APIs (Exchange Online) support clients accessing them using app-only tokens - and they have turned on this support very recently. Read about client credential flow tokens with Exchange Online APIs here: http://blogs.technet.com/b/ad/archive/2015/02/04/using-azure-ad-to-build-daemon-applications-that-call-office-365-apis.aspx, http://blogs.msdn.com/b/exchangedev/archive/2015/01/22/building-demon-or-service-apps-with-office-365-mail-calendar-and-contacts-apis-oauth2-client-credential-flow.aspx

Hope this helps.

ps: OAuth2 client credential flow doesn't issue a refresh token

Dushyant Gill
  • 3,966
  • 18
  • 14
2

You will need an access token for the specific resource you are trying to access - in this case your sharepoint site for the Office365 REST Apis.

A good read on this can be found here: https://msdn.microsoft.com/en-us/library/azure/dn645538.aspx

Assuming your {base_url} is a sharepoint site, i.e., 'https://[site_name]-my.sharepoint.com

You can either:

(1) Initially get the access and refresh tokens using your client credentials plus a resource = {base url}

or

(2) Once you have the access and refresh token from the Azure AD resource, make a refresh_token call using:

  • client_id
  • client_secret
  • grant_type = 'refresh_token'
  • resource = {base_url}
  • refresh_token = [refresh token received from Azure AD generate token response]

In this case you'll have 2 access tokens:

  1. one that can be used for Azure AD requests
  2. one that can be used for Office365 REST Api requests.

We could not/have not found a way to have a single access token be 'valid' for more than 1 resource.

Hope this helps!

Jeff Schuman
  • 772
  • 7
  • 12
  • Here is the problem that I'm having. I use "approach #1 above" and supply client_id, client_secret, grant_type="client_credentials", and resource={base_url} and receive a response that contains an "access_token" but does NOT contain a refresh_token. When I try to use that access_token to retrieve content from {base_url} with the "Authentication: Bearer " response header, I get no that "invalid_client" error referenced above. I am using the https://msdn.microsoft.com/en-us/library/azure/dn645543.aspx approach to receive an access token and that token fails when I try 2 get SP data – CDub Feb 07 '15 at 01:43
  • I can't use Approach #2 because I never get a refresh_token using the method as described here ... https://msdn.microsoft.com/en-us/library/azure/dn645543.aspx – CDub Feb 07 '15 at 01:49
  • I use grant_type="authorization_code". Give that a try. – Jeff Schuman Feb 07 '15 at 02:07
  • Also, I used their authentication 'sandbox' to get a handle on the whole process, as it shows all the params needed for each step of the authentication and authorization process. Here's a link to the sandbox: https://oauthplay.azurewebsites.net/ – Jeff Schuman Feb 07 '15 at 02:08
  • If I use grant_type="authorization_code" instead of "client_credentials" and leave the client_id, client_secret, and resource as before I get the error: "The request body must contain the following parameter: 'code'." . I don't have a code so no idea what that value is supposed to be. I've been trying to resolve this all week. There is DEFINITELY a gap there between the documentation and the way things REALLY work. I really really NEED to get this figured out. I presume it's something small but I can't find any documentation to give me the answer. – CDub Feb 07 '15 at 02:29
  • You first make a request to get the code THEN you make a request to get the access and refresh tokens. See the sandbox above to get the flow. It is really helpful. – Jeff Schuman Feb 07 '15 at 03:35
  • One VERY IMPORTANT thing to keep in mind in what I am doing is that there is no user interface in the application I am using to access Office365 data. I am following the 2-step process outlined here https://msdn.microsoft.com/en-us/library/azure/dn645543.aspx which is to (1) request an access token from Azure providing (client_id, client_secret, resource, grant_type=client_credentials), (2) use that access token to retrieve Office365 content . The sandbox you reference doesn't use this type of scenario. – CDub Feb 09 '15 at 23:22