I have written this code - this API is supposed to return user's information list of my Azure AD app (has delegated permission - User.ReadBasic.All
). I have done settings for
"TenantId": "","ClientId": "" & "ClientSecret": ""
in appsettings.json
file. But I am getting an "401 Unauthorized" error even if I sent the request with token from Postman.
namespace WebApplication4.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class UsersController : ControllerBase
{
private readonly ITokenAcquisition _tokenAcquisition;
public UsersController(ITokenAcquisition tokenAcquisition)
{
_tokenAcquisition = tokenAcquisition;
}
[HttpGet]
public async Task<IActionResult> GetUsers()
{
try
{
// Acquire the access token for Microsoft Graph
var token = await _tokenAcquisition.GetAccessTokenForUserAsync(new[] { "User.ReadBasic.All", "User.Read" });
// Create the GraphServiceClient with an authentication provider
var graphClient = new GraphServiceClient(new AuthProvider(token));
var usersRequestBuilder = graphClient.Users;
var users = await usersRequestBuilder
.GetAsync(requestConfiguration: request =>
{
request.QueryParameters.Select = new[] { "displayName", "userType", "mail" };
});
return Ok(users);
}
catch (Exception ex)
{
return StatusCode(StatusCodes.Status500InternalServerError, "An error occurred while fetching users.");
}
}
private class AuthProvider : IAuthenticationProvider
{
private readonly string _token;
public AuthProvider(string token)
{
_token = token;
}
public async Task AuthenticateRequestAsync(RequestInformation request, Dictionary<string, object>? additionalAuthenticationContext = null, CancellationToken cancellationToken = default)
{
// Set the Authorization header
request.Headers.Add("Authorization", $"Bearer {_token}");
await Task.CompletedTask;
}
}
}
}
I am attaching the image - This is how I've added token in request header.
I am also getting the correct token. But when I am sending the get request I am getting 401 Unauthorized. Instead I want the user info.
What am I doing wrong?
The error you are facing is due to not configuring the Scope in the appsettings.json.
I added the Scope as access_as_user in the Azuree AD app as shown below.
appsettings.json :
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"TenantId": "<tenantID>",
"ClientId": "<clientID>",
"Scopes": "access_as_user"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"MicrosoftGraph": {
"BaseUrl": "https://graph.microsoft.com/v1.0"
}
}
Below is the complete ASP.NET Web API code to authenticate and get a list of user information from an Azure AD app by calling the Microsoft Graph API.
UsersController.cs :
using Microsoft.AspNetCore.Mvc;
using Microsoft.Graph;
using Microsoft.Identity.Web;
using System.Net.Http.Headers;
namespace WebApplication5.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class UsersController : ControllerBase
{
private readonly ITokenAcquisition _tokenAcquisition;
private readonly ILogger<UsersController> _logger;
public UsersController(ITokenAcquisition tokenAcquisition, ILogger<UsersController> logger)
{
_tokenAcquisition = tokenAcquisition;
_logger = logger;
}
[HttpGet]
public async Task<IActionResult> GetUsers()
{
try
{
var token = await _tokenAcquisition.GetAccessTokenForUserAsync(new[] { "User.ReadBasic.All", "User.Read" });
var graphClient = new GraphServiceClient(new AuthProvider(token));
var users = await graphClient.Users
.Request()
.Select(u => new { u.DisplayName, u.UserType, u.Mail })
.GetAsync();
return Ok(users);
}
catch (Exception ex)
{
_logger.LogError(ex, "An error occurred while fetching users.");
return StatusCode(StatusCodes.Status500InternalServerError, "An error occurred while fetching users.");
}
}
private class AuthProvider : IAuthenticationProvider
{
private readonly string _token;
public AuthProvider(string token)
{
_token = token;
}
public async Task AuthenticateRequestAsync(HttpRequestMessage request)
{
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", _token);
await Task.CompletedTask;
}
}
}
}
Program.cs :
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Identity.Web;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"))
.EnableTokenAcquisitionToCallDownstreamApi()
.AddMicrosoftGraph(builder.Configuration.GetSection("MicrosoftGraph"))
.AddInMemoryTokenCaches();
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
I granted admin consent for User.ReadBasic.All and User.Read as shown below.
Postman Output :
In Postman, I configured the Authorization header with the following values.
Make sure to add the Scope as below in the Postman.
Scope : api://<clientID>/access_as_user
I added the below callback URL from Postman to the Azure AD app's Authentication settings as a Web URI.
https://oauth.pstmn.io/v1/callback
I successfully retrieved the user information list from the Azure AD app by calling the Microsoft Graph API in Postman, as shown below.