I'm experienced in .NET but pretty new to Sharepoint and Project Online. I am curious if it's MFA or what is going but I always get a
The remote server returned an error: (403) FORBIDDEN
For the code
public async Task<ProjectContext?> GetContextWithCredentialsAsync(string url, string username, string password)
{
try
{
if (url.ToUpper().StartsWith("HTTP://") || url.ToUpper().StartsWith("HTTPS://"))
{
var securePassword = new SecureString();
password.ToCharArray().ToList().ForEach(s => securePassword.AppendChar(s));
var clientContext = new ProjectContext(url)
{
Credentials = new NetworkCredential(username, securePassword)
};
clientContext.Load(clientContext.Projects);
clientContext.ExecuteQuery();
return await System.Threading.Tasks.Task.Factory.StartNew(() => { return clientContext; });
}
}
catch (Exception ex)
{
throw ex;
}
return null;
}
I have seen other similar code online doing this and I think maybe it is MFA and I need to get an auth but other links I have seen were older .NET. I am using the library: 'Microsoft.SharePointOnline.CSOM' version 16.1.24810.12000 in a .NET 8 Web API calling the code above.
Edit: It seems you have to use Entra and something else but I want a better answer for all to use. It's pretty sad when MS docs are wrong. Someone has to know the answer we can write up for .NET 8 and NOT full framework.
The closest I have so far requires a clientId and tenantId but it was done through Azure. Can you do this for a VM directly without an Azure app?
public async System.Threading.Tasks.Task
CreateConnectionProjectContext(string baseUrl, string url, string username, string password, string clientId, string tenantId)
{
var pcaConfig = PublicClientApplicationBuilder.Create(clientId).WithTenantId(tenantId);
var TokenResult = await pcaConfig.Build().AcquireTokenByUsernamePassword(new[] { baseUrl }, username, password).ExecuteAsync();
// Load ps context
var projectContext = new ProjectContext(url);
projectContext.ExecutingWebRequest += (s, e) =>
{
e.WebRequestExecutor.RequestHeaders["Authorization"] = "Bearer " + TokenResult.AccessToken;
};
projectContext.Load(projectContext.Projects);
projectContext.ExecuteQuery();
_context = projectContext;
}
}
The problem is the line of 'var pcaConfig' Can you make that up directly in Entra without an Azure Application?
.NET Framework
You need to use the SharePointOnlineCredentials for Credentials prop. Also be careful to use the right pwa url (from documentation) :
In this example, the url should be equal to : "https://Contoso.sharepoint.com/sites/pwa"
//URL should contain the pwa url ex: https://Contoso.sharepoint.com/sites/pwa
var clientContext = new ProjectContext(url);
var netcred = new NetworkCredential(username, password);
var orgIDCredential = new SharePointOnlineCredentials(netcred.UserName, netcred.SecurePassword);
clientContext.Credentials = orgIDCredential;
var projects = clientContext.Load(clientContext.Projects);
clientContext.ExecuteQuery();
if(projects.Any())
// use projects
Complete example that create project and update fields : https://github.com/OfficeDev/Project-Samples/tree/main/Create-Update-Project-Samples/Create-Update-Project-Samples
[EDIT] : Distinction .Net Core/Framework
.NET Core / .NET 8
As you mentionned in the comment there's no SharePointOnlineCredentials . You will need to obtain an OAuth access token, by creating an app registration and granting to it Sharepoint permission :
Now that you have a client configured to get OAuth tokens, you can fetch the token using passwork flow from the Microsoft Entra ID token endpoint https://login.microsoftonline.com/common/oauth2/token.
POST https://login.microsoftonline.com/common/oauth2/token Body : resource=https://...sites//pwa&client_id={appId}&grant_type=password&username={username}&password={userPass}
You can use an HttpClient to do the post, or use any OAuth library to get the token.
When you have a token you can use the ProjectContext to query Project :
var context = new ProjectContext(web);
context.ExecutingWebRequest += (sender, e) =>
{
var accessToken = // Get AccessToken
e.WebRequestExecutor.RequestHeaders["Authorization"] = "Bearer " + accessToken;
};
projectContext.Load(projectContext.Projects);
projectContext.ExecuteQuery();
A complete code example here (it uses ClientContext but it's similiar) : https://learn.microsoft.com/en-us/sharepoint/dev/sp-add-ins/using-csom-for-dotnet-standard