Alina Anjum
Alina Anjum

Reputation: 1230

Access SharePoint Online Rest API with Azure AD Authentication

I am trying to access SharePoint online Rest API using Azure AD.

I have registered App in Azure AD and Granted full access as described in this Question

After Research, I came to know that I will be able to call SharePoint Rest APIs by Client ID and Certificate.

I uploaded an SSL Certificate along with my App in Azure AD.

Now I want to get That certificate and call SharePoint Rest Api.

I am using the following code to do that by following this Article:

  public OverduePOs GetItemDetail(string ItemID, string accessToken)
        {
            try
            {




                Uri uri = new Uri(MasterData.SiteURL);

                using (var client = new SPHttpClient(uri, MasterData.UserID, MasterData.PWD))
                {
                    var listTitle = "Overdue POs List";
                    var itemPayload = new { __metadata = new { type = "SP.Data.Overdue_x0020_POs_x0020_ListListItem" } };
                    var endpointUrl = string.Format("{0}/_api/web/lists/getbytitle('{1}')/items({2})", uri, listTitle, ItemID);


                    var keyValues = new List<KeyValuePair<string, string>>
            {
                new KeyValuePair<string, string>("Authorization", "Bearer "+accessToken)
            };
                    CertificateAuthentication obj_cer = new CertificateAuthentication();
                  
                    HttpContent content = new FormUrlEncodedContent(keyValues);


                  
                      var httpClient = new HttpClient();
                    httpClient.DefaultRequestHeaders.Add("X-ARR-ClientCert", obj_cer.GetCertificate(MasterData.clientId, "35E646884017E739A7B4F63675886FFB1CEF3C96").GetHashCode().ToString());

                    httpClient.DefaultRequestHeaders.Add("Authorization", "Bearer " + accessToken);
                    httpClient.DefaultRequestHeaders.Add("Accept", "application/json"); // Specify JSON format
                    var response = httpClient.GetAsync(endpointUrl).Result;
                    var result = response.Content.ReadAsStringAsync().Result;
                    var test = JsonConvert.DeserializeObject<OverduePOs>(result.ToString());
                    return JsonConvert.DeserializeObject<OverduePOs>(result.ToString());
                }




            }
            catch (HttpRequestException ex)
            {

                return null;
            }

        }

 public class CertificateAuthentication
    {
        public ClientAssertionCertificate GetCertificate(string clientId, string thumbprint)
        {
            var certificate = GetCertificateFromStore(thumbprint);
            return new ClientAssertionCertificate(clientId, certificate);
        }
        //private static X509Certificate2 GetCertificateFromDirectory(string path, string password)
        //{
        //    return new X509Certificate2(System.IO.Path.GetFullPath(path), password, X509KeyStorageFlags.MachineKeySet);
        //}
        private static X509Certificate2 GetCertificateFromStore(string thumbprint)
        {
            var store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
            store.Open(OpenFlags.ReadOnly);
            var certificates = store.Certificates.Find(X509FindType.FindByThumbprint, thumbprint, false);
            store.Close();
            return certificates[0];
        }
    }

I have successfully got the Access Token but unable to get the certificate which is required to call SharePoint Rest API.

Can anyone Help me in this Please!

Upvotes: 1

Views: 1964

Answers (1)

Sridevi
Sridevi

Reputation: 22542

Note that, your code uses Microsoft.IdentityModel.Clients.ActiveDirectory library that is currently deprecated and no longer supported.

Alternatively, you can use Microsoft.Identity.Client package for generating access token.

In my case, I performed same steps as you in registering application and adding permissions to it:

enter image description here

Now, I ran below PowerShell script from same document that created certificates with .cer and .pfx format in specified location:

$dnsName = "mxxxxxxx.sharepoint.com"
$password = "xxxxxxx"
$folderPath = "C:\temp\certs"
$fileName = "sricert17"
$yearsValid = 10

$certStoreLocation = "cert:\LocalMachine\My"
$expirationDate = (Get-Date).AddYears($yearsValid)
    
$certificate = New-SelfSignedCertificate -DnsName $dnsName -CertStoreLocation $certStoreLocation -NotAfter $expirationDate -KeyExportPolicy Exportable -KeySpec Signature    
$certificatePath = $certStoreLocation + '\' + $certificate.Thumbprint
$filePath = $folderPath + '\' + $fileName
$securePassword = ConvertTo-SecureString -String $password -Force -AsPlainText

Export-Certificate -Cert $certificatePath -FilePath ($filePath + '.cer')
Export-PfxCertificate -Cert $certificatePath -FilePath ($filePath + '.pfx') -Password $securePassword

Response:

enter image description here

I uploaded this .cer certificate in my Azure AD application like this:

enter image description here

When I ran below c# code to generate access token and called SharePoint Online Rest API, I got response successfully like this:

using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
using Microsoft.Identity.Client;

class Program
{
    static async Task Main()
    {
        // Load the certificate from a file location
        X509Certificate2 certificate = new X509Certificate2("C:/temp/certs/mycert17.pfx", "password");

        // Create the confidential client application object
        IConfidentialClientApplication confidentialClientApplication = ConfidentialClientApplicationBuilder
            .Create("appId")
            .WithCertificate(certificate)
            .WithAuthority(new Uri("https://login.microsoftonline.com/tenantId"))
            .Build();

        // Get the access token
        string[] scopes = new string[] { "https://mxxxxxxx.sharepoint.com/.default" };
        AuthenticationResult authResult = await confidentialClientApplication.AcquireTokenForClient(scopes).ExecuteAsync();

        // Print the access token
        Console.WriteLine("Access token: {0}\n", authResult.AccessToken);

        // Call SharePoint API using the access token
        await CallSharePointApi(authResult.AccessToken);
    }

    static async Task CallSharePointApi(string accessToken)
    {
        try
        {
            Uri uri = new Uri("https://mxxxxxxxxxx.sharepoint.com"); // SharePoint URL

            using (var httpClient = new HttpClient())
            {
                var listTitle = "srilist";
                var itemID = "1"; // Replace with the actual item ID
                var endpointUrl = $"{uri}/sites/sritestsite10/_api/web/lists/getbytitle('{listTitle}')/items({itemID})";

                // Set the required headers
                httpClient.DefaultRequestHeaders.Add("Authorization", "Bearer " + accessToken);
                httpClient.DefaultRequestHeaders.Add("Accept", "application/json");

                var response = await httpClient.GetAsync(endpointUrl);
                response.EnsureSuccessStatusCode();

                var result = await response.Content.ReadAsStringAsync();
                // Process the SharePoint API response as needed
                Console.WriteLine("\nSharePoint API Response:\n" + result);
            }
        }
        catch (HttpRequestException ex)
        {
            // Handle or log the exception
            Console.WriteLine("Error calling SharePoint API: " + ex.Message);
        }
    }
}

Response:

enter image description here

Upvotes: 1

Related Questions