Search code examples
azure.net-coremicrosoft-graph-apimicrosoft-entra-id

Cannot fetch the customSecurityAttributes data from Entra ID user Profile using Microsoft Graph API in Dotnet Webapi


I cannot fetch the customSecurityAttributes data from Entra ID user Profile. I have created a dotnet 8 webapi to pull the user details. it pulls the other properties but in case of customSecurityAttributes, it only pulls the attribute set name i.e. devDetails, with the null value (no details about custom attribute names and values). Please help.

        [HttpGet("specificcust/{UUID}")]
public async Task<IActionResult> GetUserDetailsCust(string UUID)
{
    var result = await _graphClient.Users[UUID].GetAsync(requestConfiguration =>
        {
            requestConfiguration.QueryParameters.Select = new string[] { "customSecurityAttributes" };
        });

        if (result.CustomSecurityAttributes != null && result.CustomSecurityAttributes.AdditionalData != null)
        {
            foreach (var attribute in result.CustomSecurityAttributes.AdditionalData)
            {
                var json = JsonSerializer.Serialize(attribute.Value);
                Console.WriteLine($"{attribute.Key}: {json}");
                return Ok(json);
            }
        }
        else
        {
            Console.WriteLine("No custom security attributes found.");
        }
    return Ok(result.ToString());
}

My Service client:

public class GraphApiService
{
    private readonly IConfiguration _configuration;
    private readonly GraphServiceClient _graphClient;
    public GraphServiceClient GraphClient => _graphClient;

public GraphApiService(IConfiguration configuration)
{
    _configuration = configuration;
    _graphClient = GetGraphServiceClient();
}

private GraphServiceClient GetGraphServiceClient()
{
    var clientSecretCredential = new ClientSecretCredential(
        _configuration["AzureAd:TenantId"],
        _configuration["AzureAd:ClientId"],
        _configuration["AzureAd:ClientSecret"]
    );

    return new GraphServiceClient(clientSecretCredential, 
    new[] { "https://graph.microsoft.com/.default" });
}

}

My output:

devDetails: {}

Edit: enter image description here

Edit: enter image description here enter image description here

Edit 2: It worked with Node JS (Express JS)

const express = require("express");
const app = express();

const { Client } = require("@microsoft/microsoft-graph-client");
const { ClientSecretCredential } = require("@azure/identity");
CUS_PORT = 3500;
const fetch = require("node-fetch");

if (!globalThis.fetch) {
  globalThis.fetch = fetch;
}

app.use(express.json({ limit: "5mb" }));
app.use(express.urlencoded({ extended: false }));

const tenantId = "";
const clientId = "";
const clientSecret = "";
const UUID = "";

const credential = new ClientSecretCredential(tenantId, clientId, clientSecret);

const client = Client.init({
  authProvider: async (done) => {
    try {
      const accessToken = await credential.getToken(
        "https://graph.microsoft.com/.default"
      );
      done(null, accessToken.token);
    } catch (error) {
      done(error, null);
    }
  },
});

app.get("/getData", async (req, res) => {
  try {
    // const UUID = req.params.UUID;
    const result = await client
      .api(`/users/${UUID}`)
      .select("customSecurityAttributes")
      .get();

    res.status(200).send(result);
  } catch (error) {
    console.error(error);
    res.status(500).send(error);
  }
});

app.listen(CUS_PORT, () => {
  console.log(
    `API is running on ${CUS_PORT} port started at ${new Date().toDateString()} ${new Date().toLocaleTimeString()}`
  );
});

Result:

{
  "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#users(customSecurityAttributes)/$entity",
  "customSecurityAttributes": {
    "devDetails": {
      "@odata.type": "#microsoft.graph.customSecurityAttributeValue",
      "devLocation": "Canada",
      "devOrAdmin": 1,
      "devLab": "BIRG"
    }
  }
}

Solution

  • Note that: To fetch the custom security attribute assignments for a user, you need to assign the Attribute Assignment Reader role to the application and grant CustomSecAttributeAssignment.Read.All API permission to the application. Refer this MsDoc

    The user has custom security attribute assignments like below:

    enter image description here

    Grant CustomSecAttributeAssignment.Read.All API permission:

    enter image description here

    Assign the Attribute Assignment Reader role to the application

    enter image description here

    Now for sample I used the below code and, got the custom security attribute assignments of a user successfully:

    class Program
    {
        private static async Task Main(string[] args)
        {
            string clientId = "ClientID"; 
            string clientSecret = "Secret"; 
            string tenantId = "TenantID"; 
    
            var clientSecretCredential = new ClientSecretCredential(tenantId, clientId, clientSecret);
            var graphClient = new GraphServiceClient(clientSecretCredential);
            string userId = "UserID"; 
    
            // Fetch custom security attributes
            await GetCustomSecurityAttributes(graphClient, userId);
        }
    
        private static async Task GetCustomSecurityAttributes(GraphServiceClient graphClient, string userId)
        {
            try
            {
                var result = await graphClient.Users[userId].GetAsync(requestConfiguration =>
                {
                    requestConfiguration.QueryParameters.Select = new string[] { "customSecurityAttributes" };
                });
    
                if (result.CustomSecurityAttributes != null && result.CustomSecurityAttributes.AdditionalData != null)
                {
                    foreach (var attribute in result.CustomSecurityAttributes.AdditionalData)
                    {
                        Console.WriteLine($"{attribute.Key}: {attribute.Value}");
                    }
                }
                else
                {
                    Console.WriteLine("No custom security attributes found.");
                }
            }
            catch (ServiceException ex)
            {
                Console.WriteLine($"Error fetching user details: {ex.Message}");
            }
        }
    }
    

    enter image description here

    enter image description here

    UPDATE Try the below:

     private static async Task GetCustomSecurityAttributes(GraphServiceClient graphClient, string userId)
        {
            try
            {
                
                var result = await graphClient.Users[userId].GetAsync();
                if (result.CustomSecurityAttributes != null && result.CustomSecurityAttributes.AdditionalData != null)
                {
                    
                    foreach (var attribute in result.CustomSecurityAttributes.AdditionalData)
                    {
                        if (attribute.Value is Microsoft.Kiota.Abstractions.Serialization.UntypedObject)
                        {
                            var json = JsonSerializer.Serialize(attribute.Value);
                            Console.WriteLine($"{attribute.Key}: {json}");
                        }
                        else
                        {
                            Console.WriteLine($"{attribute.Key}: {attribute.Value}");
                        }
                    }
                }
                else
                {
                    Console.WriteLine("No custom security attributes found.");
                }
            }