Requirement is to upload document to a Sharepoint site using A WPF Desktop Application. I registred my app in Azure, used the Client ID, Thumbprint, Tenant Id in my code to procure Access Token. My Code was able to get the access token but as soon as it runs Context.ExecuteQuery() it fails with:
The remote server returned an error:(401) Unauthorized" even after getting access Token
string SiteUrl = "https://<Tenant>.sharepoint.com/teams/<sitename>/";
string clientId = "XXXXXXXXXXXXXXXXXXXXXXXXXX";
string certThumprint = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
var scopes = new string[] { "https://<tenant>.sharepoint.com/.default" };
string tenantId = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
var accessToken = await GetApplicationAuthenticatedClient(clientId, certThumprint, scopes, tenantId);
using (ClientContext CContext = GetClientContextWithAccessToken(SiteUrl, accessToken))
{
FileCreationInformation newFile = new FileCreationInformation();
byte[] FileContent = System.IO.File.ReadAllBytes(FileName);
newFile.ContentStream = new MemoryStream(FileContent);
newFile.Url = Path.GetFileName(FileName);
Web web = CContext.Web;
List DocumentLibrary = web.Lists.GetByTitle(DocLibrary);
CContext.Load(DocumentLibrary);
CContext.ExecuteQuery();
Folder Clientfolder =null;
if (ClientSubFolder == "")
{
Clientfolder = DocumentLibrary.RootFolder;
}
else
{
Clientfolder = DocumentLibrary.RootFolder.Folders.Add(ClientSubFolder);
Clientfolder.Update();
}
Microsoft.SharePoint.Client.File uploadFile = Clientfolder.Files.Add(newFile);
CContext.Load(uploadFile);
CContext.ExecuteQuery();
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("The File has been uploaded" + Environment.NewLine + "FileUrl -->" + SiteUrl + "/" + DocLibrary + "/" + ClientSubFolder + "/" + Path.GetFileName(FileName));
}
#endregion
}
catch (Exception exp)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(exp.Message + Environment.NewLine + exp.StackTrace);
MessageBox.Show(exp.Message + " (Ref: 401)");
}
finally
{
Console.ReadLine();
}
}
internal static async Task<string> GetApplicationAuthenticatedClient(string clientId, string certThumprint, string[] scopes, string tenantId)
{
X509Certificate2 certificate = GetAppOnlyCertificate(certThumprint);
IConfidentialClientApplication clientApp = ConfidentialClientApplicationBuilder
.Create(clientId)
.WithCertificate(certificate)
.WithTenantId(tenantId)
.Build();
AuthenticationResult authResult = await clientApp.AcquireTokenForClient(scopes).ExecuteAsync();
string accessToken = authResult.AccessToken;
return accessToken;
}
public static ClientContext GetClientContextWithAccessToken(string targetUrl, string accessToken)
{
ClientContext clientContext = new ClientContext(targetUrl);
clientContext.ExecutingWebRequest +=
delegate (object oSender, WebRequestEventArgs webRequestEventArgs)
{
webRequestEventArgs.WebRequestExecutor.RequestHeaders["Authorization"] =
"Bearer " + accessToken;
};
return clientContext;
}
private static X509Certificate2 GetAppOnlyCertificate(string thumbPrint)
{
X509Certificate2 appOnlyCertificate = null;
X509Store certStore = new X509Store(StoreName.My, StoreLocation.CurrentUser);
certStore.Open(OpenFlags.ReadOnly);
X509Certificate2Collection certCollection = certStore.Certificates.Find(X509FindType.FindByThumbprint, thumbPrint, false);
if (certCollection.Count > 0)
{
appOnlyCertificate = certCollection[0];
}
certStore.Close();
return appOnlyCertificate;
}
While I have following API permissions in App Registrations: