In my humble opinion, Angular client app + .net core web api, this scenario, we should put the authentication and authorization part into angular project, so that users could sign in and generate access token to call API.
Inside the API, if we have the requirement to call MS graph API, we could use on-behalf-of flow to generate access token. Using on-behalf-of flow in the api project, we just need to add authentication scheme and inject graph SDK or token acquisition service. This flow, maybe you can take a look at this code snippet.
StringValues authorizationToken;
HttpContext.Request.Headers.TryGetValue("Authorization", out authorizationToken);
var token = authorizationToken.ToString().Replace("Bearer ","");
var scopes = new[] { "User.Read.All" };
var tenantId = "xxxx";
var clientId = "xxxx";
var clientSecret = "xxxx";
var onBehalfOfCredential = new OnBehalfOfCredential(tenantId, clientId, clientSecret, token);
var tokenRequestContext = new TokenRequestContext(scopes);
var token2 = onBehalfOfCredential.GetTokenAsync(tokenRequestContext, new CancellationToken()).Result.Token;
var graphClient = new GraphServiceClient(onBehalfOfCredential, scopes);
var user = await graphClient.Users.GetAsync();
By the way, when we sign in with auth code flow, it should ask us to give consent after entering password and user name if we didn't give admin consent in Azure AD api permission blade, for client credential flow, it's necessary to give admin consent. And if we used client credential flow for multi-tenant scenario, I'm afraid we should pass the admin consent step in advance.
https://login.microsoftonline.com/common/adminconsent?client_id=xxxe&state=12345&redirect_uri=http://localhost/myapp/permissions
client credential flow code sample, this is based on package Microsoft.Graph v4.x
, using v5.x should have some differences:
using Microsoft.Graph;
using Azure.Identity;
var scopes = new[] { "https://graph.microsoft.com/.default" };
var tenantId = "tenant_name.onmicrosoft.com";//common for multi-tenant
var clientId = "aad_app_id";
var clientSecret = "client_secret";
var clientSecretCredential = new ClientSecretCredential(
tenantId, clientId, clientSecret);
var graphClient = new GraphServiceClient(clientSecretCredential, scopes);
var res = await graphClient.Users["{user-id}"].Messages["{message-id}"].Request().GetAsync();