How can I resolve the issue of receiving HTTP error 403 "Forbidden" when trying to upload and add an item to a Sharepoint list using Microsoft Graph and C#? I have retrieved a token using a client ID and secret from Azure/Entra, and have tried to use a certificate both ways with the same result. I can create a list without issue, but continue to receive the error when trying to upload a file to a newly created list. I have changed the Sharepoint permission from write to full control, but the problem persists.
Here is the code I'm using both getting token with App_id, secret and the other with certificate.
public static async Task<string> GetGraphToken(string clientId, string clientSecret, string tenantId)
{
string retValue = "";
string authority = "https://login.microsoftonline.com/" + tenantId;
var app = ConfidentialClientApplicationBuilder
.Create(clientId)
.WithClientSecret(clientSecret)
.WithAuthority(new Uri(authority))
.Build();
var scopes = new[] { "https://graph.microsoft.com/.default" };
try
{
var result = await app.AcquireTokenForClient(scopes)
.ExecuteAsync();
Console.WriteLine($"Access token: {result.AccessToken}");
retValue = result.AccessToken;
}
catch (MsalServiceException ex)
{
Console.WriteLine($"Error acquiring token: {ex.Message}");
}
return retValue;
}
public static async Task<string> GetGraphTokenCertificate(string clientId, string clientSecret, string tenantId, string certificateThumbprint)
{
string retValue = "";
string authority = $"https://login.microsoftonline.com/{tenantId}";
var cert = GetCertificateByThumbprint(certificateThumbprint);
var app = ConfidentialClientApplicationBuilder.Create(clientId)
.WithAuthority(authority)
.WithCertificate(cert)
.Build();
string[] scopes = new string[] { "https://graph.microsoft.com/.default" };
var result = await app.AcquireTokenForClient(scopes).ExecuteAsync();
retValue = result.AccessToken;
// Now you can use the access token to authenticate with SharePoint using CSOM
return retValue;
}
static X509Certificate2 GetCertificateByThumbprint(string thumbprint)
{
X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly);
var certificates = store.Certificates.Find(X509FindType.FindByThumbprint, thumbprint, validOnly: false);
store.Close();
return certificates.Count > 0 ? certificates[0] : null;
}
public static async Task<string> ListCreate(string accessToken, string siteId, string folderId, string listName)
{
string retValue = "";
// Microsoft Graph endpoint to create a list
string graphUrl = "https://graph.microsoft.com/v1.0/sites/{site-id}/lists";
// Folder relative URL where the list will be created
//string folderUrl = "/sites/{site-name}/lists";
// Define columns
var columns = new List<ColumnDefinition>
{
new ColumnDefinition
{
Name = "Title",
Text = new TextColumn()
},
new ColumnDefinition
{
Name = "Modified",
DateTime = new DateTimeColumn()
},
new ColumnDefinition
{
Name = "Created",
DateTime = new DateTimeColumn()
},
new ColumnDefinition
{
Name = "BatchName",
Text = new TextColumn()
},
new ColumnDefinition
{
Name = "FileName",
Text = new TextColumn()
},
new ColumnDefinition
{
Name = "ScanDate",
DateTime = new DateTimeColumn()
},
new ColumnDefinition
{
Name = "Processed By",
PersonOrGroup = new PersonOrGroupColumn()
},
new ColumnDefinition
{
Name = "Created By",
PersonOrGroup = new PersonOrGroupColumn()
},
new ColumnDefinition
{
Name = "Modified By",
PersonOrGroup = new PersonOrGroupColumn()
},
// Attachment column
//new ColumnDefinition
//{
// Name = "Attachments",
// Attachments = new AttachmentColumn()
//}
// Add more columns as needed
};
// Create a JSON payload for creating the list with columns
string jsonPayload = JsonConvert.SerializeObject(new
{
displayName = listName,
list = new
{
template = "genericList",
AllowAttachments = true, // Enable attachments
columns = columns
},
parentReference = new
{
driveId = folderId // specify the parent folder ID
}
});
// Prepare and send HTTP request to Microsoft Graph API
using (var httpClient = new HttpClient())
{
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
var content = new StringContent(jsonPayload, Encoding.UTF8, "application/json");
var response = await httpClient.PostAsync(graphUrl.Replace("{site-id}", siteId).Replace("{site-name}", siteId), content);
if (response.IsSuccessStatusCode)
{
Console.WriteLine("List with columns, attachment, and date columns created successfully.");
}
else
{
Console.WriteLine($"Failed to create list with columns, attachment, and date columns. StatusCode: {response.StatusCode}");
}
}
return retValue;
}
public static async Task<string> SendToSharePoint(string token, string siteId, string listId, string title, string batchName, string fileName, string scanDate, string attachmentin64base)
{
string retValue = "";
if (!string.IsNullOrEmpty(token))
{
var item = new
{
fields = new
{
Title = title,
Created = DateTime.Now.ToString("MM/dd/yyyy h:mm tt"),
BatchName = batchName,
FileName = fileName,
ScanDate = scanDate,
},
/*
attachments = new[]
{
new
{
fileName = fileName,
contentBytes = attachmentin64base
}
}
*/
};
await AddListItem(token, siteId, listId, item);
}
return retValue;
}
public static async Task<string> AddListItem(string accessToken, string siteId, string listId, object item)
{
string retValue = "";
string addItemUrl = $"https://graph.microsoft.com/v1.0/sites/{siteId}/lists/{listId}/items";
using (var httpClient = new HttpClient())
{
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
var itemContent = new StringContent(JsonConvert.SerializeObject(item), Encoding.UTF8, "application/json");
var response = await httpClient.PostAsync(addItemUrl, itemContent);
if (response.IsSuccessStatusCode)
{
Console.WriteLine("Item added successfully.");
}
else
{
Console.WriteLine($"Failed to add item: {response.ReasonPhrase}");
}
}
return retValue;
}