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 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"
}
}
}
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:
Grant CustomSecAttributeAssignment.Read.All
API permission:
Assign the Attribute Assignment Reader role to the application
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}");
}
}
}
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.");
}
}