I'm working on migrating a application that uses Azure AD Graph and MSAL Authorization to the newer Microsoft Graph API and MSAL.NET. Below is the code snippet that retrieves direct reports for a user:
public async Task<List<Microsoft.Azure.ActiveDirectory.GraphClient.User>> GetDirectReports(string objectId)
{
List<Microsoft.Azure.ActiveDirectory.GraphClient.User> reports = new List<Microsoft.Azure.ActiveDirectory.GraphClient.User>();
try
{
var client = AuthenticationHelper.GetClient();
IUser user = await client.Users.GetByObjectId(objectId).ExecuteAsync();
var userFetcher = user as IUserFetcher;
IPagedCollection<IDirectoryObject> directReports = await userFetcher.DirectReports.ExecuteAsync();
do
{
List<IDirectoryObject> directoryObjects = directReports.CurrentPage.ToList();
foreach (IDirectoryObject directoryObject in directoryObjects)
{
if (directoryObject is Microsoft.Azure.ActiveDirectory.GraphClient.User)
{
reports.Add((Microsoft.Azure.ActiveDirectory.GraphClient.User)directoryObject);
}
}
directReports = await directReports.GetNextPageAsync();
} while (directReports != null);
}
catch (Exception e)
{
if (Request.QueryString["reauth"] == "True")
{
HttpContext.GetOwinContext()
.Authentication.Challenge(OpenIdConnectAuthenticationDefaults.AuthenticationType);
}
ViewBag.ErrorMessage = "Authorization error occurred.";
}
}
I attempted to migrate this code to use Microsoft Graph API and MSAL.NET, but I'm facing issues with delegation and authorization. Specifically, the migrated code does not seem to handle delegated permissions properly, and I'm getting errors when trying to fetch direct reports.
Here is the migrated code snippet:
public async Task<List<User>> GetDirectReports(string userId)
{
List<User> reports = new List<User>();
try
{
var graphClient = new GraphServiceClient(new DelegateAuthenticationProvider(async (requestMessage) =>
{
var token = await GetAccessTokenAsync();
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
}));
var directReports = await graphClient.Users[userId].DirectReports.Request().GetAsync();
do
{
foreach (var report in directReports.CurrentPage)
{
if (report is User user)
{
reports.Add(user);
}
}
directReports = directReports.NextPageRequest != null ? await directReports.NextPageRequest.GetAsync() : null;
} while (directReports != null);
}
catch (ServiceException ex)
{
if (ex.StatusCode == System.Net.HttpStatusCode.Unauthorized)
{
// Handle reauthorization logic
}
else
{
throw;
}
}
return reports;
}
Share point authentication create hand shake and below are the autherization block in startauth.cs
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
ClientId = clientId,
Authority = Authority,
RedirectUri = postLogoutRedirectUri,
PostLogoutRedirectUri = postLogoutRedirectUri,
Scope = $"openid profile {scopes}", // Include Microsoft Graph scopes
TokenValidationParameters = new TokenValidationParameters
{
RoleClaimType = "roles",
},
Notifications = new OpenIdConnectAuthenticationNotifications
{
AuthorizationCodeReceived = async (context) =>
{
var code = context.Code;
var userObjectId = context.AuthenticationTicket.Identity.FindFirst(
";).Value;
IConfidentialClientApplication Iconfidentialapp;
if (!string.IsNullOrEmpty(certName))
{
// Load the certificate
X509Certificate2 cert = LoadCertificate(certName);
if (cert == null)
{
throw new Exception("Certificate not found.");
}
// Create the confidential client application with the certificate
Iconfidentialapp = ConfidentialClientApplicationBuilder.Create(clientId)
.WithAuthority(Authority)
.WithCertificate(cert)
.Build();
}
else
{
// Create the confidential client application with the client secret
Iconfidentialapp = ConfidentialClientApplicationBuilder.Create(clientId)
.WithAuthority(Authority)
.WithClientSecret(clientSecret)
.Build();
}
// Acquire a token using the authorization code
var result = await Iconfidentialapp.AcquireTokenByAuthorizationCode(scopes.Split(' '), code)
.ExecuteAsync();
// Store the token in a helper class or session
AuthenticationHelper.token = result.AccessToken;
}
}
});
Issues Encountered:
Severity Code Description Project File Line Suppression State Error CS1061 'DirectReportsRequestBuilder' does not contain a definition for 'Request' and no accessible extension method 'Request' accepting a first argument of type 'DirectReportsRequestBuilder' could be found (are you missing a using directive or an assembly reference?)
Severity Code Description Project File Line Suppression State Error CS0246 The type or namespace name 'DelegateAuthenticationProvider' could not be found (are you missing a using directive or an assembly reference?)
Am I doing right or any other method or any other way to achieve the requirement.
Referred MS articles:
I'm working on migrating a application that uses Azure AD Graph and MSAL Authorization to the newer Microsoft Graph API and MSAL.NET. Below is the code snippet that retrieves direct reports for a user:
public async Task<List<Microsoft.Azure.ActiveDirectory.GraphClient.User>> GetDirectReports(string objectId)
{
List<Microsoft.Azure.ActiveDirectory.GraphClient.User> reports = new List<Microsoft.Azure.ActiveDirectory.GraphClient.User>();
try
{
var client = AuthenticationHelper.GetClient();
IUser user = await client.Users.GetByObjectId(objectId).ExecuteAsync();
var userFetcher = user as IUserFetcher;
IPagedCollection<IDirectoryObject> directReports = await userFetcher.DirectReports.ExecuteAsync();
do
{
List<IDirectoryObject> directoryObjects = directReports.CurrentPage.ToList();
foreach (IDirectoryObject directoryObject in directoryObjects)
{
if (directoryObject is Microsoft.Azure.ActiveDirectory.GraphClient.User)
{
reports.Add((Microsoft.Azure.ActiveDirectory.GraphClient.User)directoryObject);
}
}
directReports = await directReports.GetNextPageAsync();
} while (directReports != null);
}
catch (Exception e)
{
if (Request.QueryString["reauth"] == "True")
{
HttpContext.GetOwinContext()
.Authentication.Challenge(OpenIdConnectAuthenticationDefaults.AuthenticationType);
}
ViewBag.ErrorMessage = "Authorization error occurred.";
}
}
I attempted to migrate this code to use Microsoft Graph API and MSAL.NET, but I'm facing issues with delegation and authorization. Specifically, the migrated code does not seem to handle delegated permissions properly, and I'm getting errors when trying to fetch direct reports.
Here is the migrated code snippet:
public async Task<List<User>> GetDirectReports(string userId)
{
List<User> reports = new List<User>();
try
{
var graphClient = new GraphServiceClient(new DelegateAuthenticationProvider(async (requestMessage) =>
{
var token = await GetAccessTokenAsync();
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
}));
var directReports = await graphClient.Users[userId].DirectReports.Request().GetAsync();
do
{
foreach (var report in directReports.CurrentPage)
{
if (report is User user)
{
reports.Add(user);
}
}
directReports = directReports.NextPageRequest != null ? await directReports.NextPageRequest.GetAsync() : null;
} while (directReports != null);
}
catch (ServiceException ex)
{
if (ex.StatusCode == System.Net.HttpStatusCode.Unauthorized)
{
// Handle reauthorization logic
}
else
{
throw;
}
}
return reports;
}
Share point authentication create hand shake and below are the autherization block in startauth.cs
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
ClientId = clientId,
Authority = Authority,
RedirectUri = postLogoutRedirectUri,
PostLogoutRedirectUri = postLogoutRedirectUri,
Scope = $"openid profile {scopes}", // Include Microsoft Graph scopes
TokenValidationParameters = new TokenValidationParameters
{
RoleClaimType = "roles",
},
Notifications = new OpenIdConnectAuthenticationNotifications
{
AuthorizationCodeReceived = async (context) =>
{
var code = context.Code;
var userObjectId = context.AuthenticationTicket.Identity.FindFirst(
"http://schemas.microsoft/identity/claims/objectidentifier").Value;
IConfidentialClientApplication Iconfidentialapp;
if (!string.IsNullOrEmpty(certName))
{
// Load the certificate
X509Certificate2 cert = LoadCertificate(certName);
if (cert == null)
{
throw new Exception("Certificate not found.");
}
// Create the confidential client application with the certificate
Iconfidentialapp = ConfidentialClientApplicationBuilder.Create(clientId)
.WithAuthority(Authority)
.WithCertificate(cert)
.Build();
}
else
{
// Create the confidential client application with the client secret
Iconfidentialapp = ConfidentialClientApplicationBuilder.Create(clientId)
.WithAuthority(Authority)
.WithClientSecret(clientSecret)
.Build();
}
// Acquire a token using the authorization code
var result = await Iconfidentialapp.AcquireTokenByAuthorizationCode(scopes.Split(' '), code)
.ExecuteAsync();
// Store the token in a helper class or session
AuthenticationHelper.token = result.AccessToken;
}
}
});
Issues Encountered:
Severity Code Description Project File Line Suppression State Error CS1061 'DirectReportsRequestBuilder' does not contain a definition for 'Request' and no accessible extension method 'Request' accepting a first argument of type 'DirectReportsRequestBuilder' could be found (are you missing a using directive or an assembly reference?)
Severity Code Description Project File Line Suppression State Error CS0246 The type or namespace name 'DelegateAuthenticationProvider' could not be found (are you missing a using directive or an assembly reference?)
Am I doing right or any other method or any other way to achieve the requirement.
Referred MS articles: https://learn.microsoft/en-us/graph/migrate-azure-ad-graph-client-libraries
Share Improve this question edited Mar 17 at 10:15 Nachiappan R asked Mar 17 at 8:31 Nachiappan RNachiappan R 1841 gold badge1 silver badge20 bronze badges 9 | Show 4 more comments1 Answer
Reset to default 0To make use Microsoft Graph API to call the APIs, you can make use of MSAL (Microsoft Authentication Library) to acquire a token. Refer this Microsoft Document and choose a Microsoft Authentication provider : Choose a Microsoft Graph authentication provider - Microsoft Graph | Microsoft Learn
Grant User.Read.All
API permission:
And make use of below code:
using Azure.Identity;
using Microsoft.Graph;
using Newtonsoft.Json;
using System;
using System.Threading.Tasks;
public class GraphAPIExample
{
private static string[] scopes = new[] { "User.Read.All" };
private static string tenantId = "TenantID";
private static string clientId = "ClientID";
private static Uri redirectUri = new Uri("http://localhost");
private static InteractiveBrowserCredentialOptions options = new InteractiveBrowserCredentialOptions
{
TenantId = tenantId,
ClientId = clientId,
AuthorityHost = AzureAuthorityHosts.AzurePublicCloud,
RedirectUri = redirectUri
};
public static async Task Main(string[] args)
{
try
{
var interactiveCredential = new InteractiveBrowserCredential(options);
var graphClient = new GraphServiceClient(interactiveCredential, scopes);
string userId = "UserID";
await GetDirectReportsForUserAsync(graphClient, userId);
}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex.Message}");
}
}
public static async Task GetDirectReportsForUserAsync(GraphServiceClient graphClient, string userId)
{
try
{
var directReportsResponse = await graphClient.Users[userId].DirectReports.GetAsync();
string jsonResponse = JsonConvert.SerializeObject(directReportsResponse, Formatting.Indented);
Console.WriteLine("Full Direct Reports Response:");
Console.WriteLine(jsonResponse);
}
catch (ServiceException ex)
{
Console.WriteLine($"Error calling Graph API: {ex.Message}");
}
}
}
If you want to use Authorization code flow make use of below code:
var scopes = new[] { "User.Read" };
var tenantId = "TenantID";
var clientId = "ClientID";
var clientSecret = "Secret";
var authorizationCode = "AUTH_CODE_FROM_REDIRECT";
var options = new AuthorizationCodeCredentialOptions
{
AuthorityHost = AzureAuthorityHosts.AzurePublicCloud,
};
var authCodeCredential = new AuthorizationCodeCredential(
tenantId, clientId, clientSecret, authorizationCode, options);
var graphClient = new GraphServiceClient(authCodeCredential, scopes);
To get authorizationCode
run the below in the browser and sign in and copy the code value:
https://login.microsoftonline/TenantID/oauth2/v2.0/authorize?
&client_id=ClientID
&response_type=code
&redirect_uri=https://jwt.ms
&response_mode=query
&scope=User.Read.All
&state=12345
graphClient.Users[userId].DirectReports.GetAsync()
without Request() – Rukmini Commented Mar 17 at 10:26