Search code examples
c#resthttpoauth-2.0sharepoint-online

How to request an access token from OAuth using System.Net.Http? 401 Error


Context

I am developing a simple application that requires to receive List Data from a company Online SharePoint site. In order to make REST requests, I must first retrieve an access token from Microsoft's access control service. Despite attempting some tutorials and reading documentation, I am new to REST/HTTP am am failing to do so.

What have I tried?

  • Used SharePoint appregnew.aspx to register my app, and generate "Client ID" and "Client Secret" values. https://[sitename].sharepoint.com/_layouts/15/appregnew.aspx
  • Used Sharepoint appinv.aspx to authorize my app with read control and generate a "Tenant ID". https://[sitename].sharepoint.com/_layouts/15/appinv.aspx
<AppPermissionRequests AllowAppOnlyPolicy="true">
    <AppPermissionRequest Scope="http://sharepoint/content/sitecollection/web" Right="Read"/>
</AppPermissionRequests>
  • Used SharePoint AppPrincipals.aspx to verify Tenant ID. https://[sitename].sharepoint.com/_layouts/15/AppPrincipals.aspx
  • Attempted several methods of formatting the request with the following being the latest:

Updated

// Variables removed for security
class Program
{
    static void Main(string[] args)
    {               
        WebRequest myWebRequest;
        string stGetAccessTokenUrl = "https://accounts.accesscontrol.windows.net/{0}/tokens/OAuth/2";

        string tenantID         = "myTenantID";
        string resourceID       = "00000003-0000-0ff1-ce00-000000000000";
        string stClientID       = "myClientID";
        string stClientSecret   = "myClientSecret";
        string stSiteDomain     = "[myCompany].sharepoint.com";

        // URL Format
        stGetAccessTokenUrl = string.Format(stGetAccessTokenUrl, tenantID);
        myWebRequest = WebRequest.Create(stGetAccessTokenUrl);
        myWebRequest.ContentType = "application/x-www-form-urlencoded";
        myWebRequest.Method = "POST";

        // Add the below body attributes to the request
        var postData = "grant_type=client_credentials";
        postData += "&client_id=" + stClientID + "@" + tenantID;
        postData += "&client_secret=" + stClientSecret;
        postData += "&resource=" + resourceID + "/" + stSiteDomain + "@" + tenantID;
        var data = Encoding.ASCII.GetBytes(postData);

        using (var stream = myWebRequest.GetRequestStream())
        {
            stream.Write(data, 0, data.Length);
        }
            
        var response = (HttpWebResponse)myWebRequest.GetResponse();
    }
}

What doesn't work?

I receive a 401 Unauthorized error despite the app having been assigned permissions.

Any help would be greatly appreciated!


Solution

  • Apologies, I forgot to return to this question upon resolving the issue. Credit to "Michael Han" within the comments of his own answer.

    Answer

    By default, the SharePoint app-only permissions is disabled for the tenant. A tenant administrator must first run the following cmdlet in PowerShell:

    Set-SPOTenant -DisableCustomAppAuthentication $false
    

    This parameter supersedes all other privilege settings and must first be configured.