Token failed : 401 Forbidden Error connecting to Sharepoint using pnpframework

358 views Asked by At

I am writing a web app that I would like to have access to Sharepoint Document Libraries from a particular site using the currently logged on user credentials. I have looked at a number of articles that suggest using the PnP Framework and using a certificate instead of the client/secret ids.

I have tried both, the code of which is below:

string siteCollectionURL = "https://mycompanyname.sharepoint.com/sites/staffportal";
       
        var authManager = new AuthenticationManager(ApplicationId, "C:\\pathtopfxfile\certifcatefx.pfx", "certificatepassword", "https://mycompany.sharepoint.com/sites/staffportal");
        using (var clientContext = authManager.GetACSAppOnlyContext(siteCollectionURL,ApplicationId,ClientSecretId))
        {
            clientContext.Load(clientContext.Web, p => p.Title);
            clientContext.ExecuteQuery();
            return Ok(clientContext.Web.Title);
        }

Unfortunately on the ExecuteQuery line I am consistently getting the 401 error, indicating that I am not authorized.

I registered the app in Azure -> Enterprise applications:

App Overview page

Certificate

API Permissions

I have checked the following articles:

How to use the PnP Framework in a c# application

Secure Authentication of SharePoint with PnP Framework with C#(Code)

And tried the code snippets, but I cannot seem to find anything that suggests using the currently logged in user to the Web app.(see screen shot) - the user is a global administrator

Test Site showing currently logged on Microsoft 365 User

Below is the error:

Error Message

Any suggestions would be much appreciated.

Regards, Darren

UPDATE TO ARTICLE

jimas13's link is what pointed me in the right direction. The tweaks I mentioned in the comment I have posted below for anyone wanting to write an MVC C# web app. This does require that the app needs to be registered and needs a self-signed certificate setup.

The two Async lines need to be written as follows:

public static async Task<AuthenticationResult> GetToken(IConfidentialClientApplication app, string[] scopes)
    {
  
            return await app.AcquireTokenForClient(scopes).ExecuteAsync();
    }

    public static async Task<Web> GetClientContext(string Uri,AuthenticationResult authResult)
    {
        using (var clientContext = ContextHelper.GetClientContext(Uri, authResult.AccessToken))
        {
            Web web = clientContext.Web;
            clientContext.Load(web);
            await clientContext.ExecuteQueryAsync();
            return web;
        }
    }

The rest of the code is here:

 public IActionResult Index()
    {
        AuthenticationConfiguration.AuthenticationConfiguration config = AuthenticationConfiguration.AuthenticationConfiguration.ReadFromJsonFile("appsettings.json");
        string siteURL = config.SiteUrl;
        string[] scopes = new string[] { config.Scope };
        CertificateDescription certificate = config.Certificate;
        ICertificateLoader certificateLoader = new DefaultCertificateLoader();
        certificateLoader.LoadIfNeeded(certificate);

        IConfidentialClientApplication app = ConfidentialClientApplicationBuilder.Create(config.ClientId)
            .WithCertificate(certificate.Certificate)
            .WithTenantId(config.Tenant)
            .WithAuthority(config.Authority)
            .Build();

       AuthenticationResult result = GetToken(app, scopes).Result;
        Web WebSite = GetClientContext(siteURL, result).Result;
      
        return Ok(WebSite.Title);
    }

The .SiteUrl and .Scope were added to the AuthenticationConfiguration.cs file as a property and then also added to the appsettings.json file.

0

There are 0 answers