I’m trying to build a small C# console app that lists all Azure AD / Entra ID groups and the users inside them (including nested members).
The end goal is to sync these groups and users into Dataverse for a Power Apps Canvas App.


What I’ve done so far

  • I installed the official Microsoft Graph SDK and Azure.Identity packages:

    dotnet add package Microsoft.Graph
    dotnet add package Azure.Identity
    
    
  • I followed Microsoft’s examples that use client-credentials authentication:

    var credential = new ClientSecretCredential(tenantId, clientId, clientSecret);
    var graph = new GraphServiceClient(credential, new[] { "https://graph.microsoft.com/.default" });
    var groups = await graph.Groups.GetAsync();
    
    
  • I understand that this requires an App Registration in Entra ID (to get Tenant ID, Client ID, and Client Secret) and that the app must have Application permissions like Directory.Read.All (with admin consent).


My problem

I only have a normal user account in Entra ID — I’m not a global admin or app-registration admin.
Because of that, I can’t register an application or grant those permissions myself.

So my questions are:

  1. Is there any way for a non-admin user to call Microsoft Graph to read group and user data programmatically in C#?
    (for example, using delegated permissions, or an alternative flow that doesn’t require app-registration rights?)

  2. If not, what’s the recommended workaround for developers who don’t have admin access —
    should we ask an admin to register the app and give us the credentials,
    or is there another safe pattern (e.g. using a service principal the organization already has)?

  3. Once the App Registration is created by an admin, am I correct that I can keep the Tenant ID, Client ID, and Client Secret in environment variables (or “User Secrets” in .NET) so they aren’t hard-coded?


What I’m aiming for

  • Read all groups (/groups)

  • For each group, read its transitive members (/groups/{id}/transitiveMembers) to include nested group users

  • Later, save the results into SQL and push to Dataverse

3 Replies 3

Depending on your kind of credentials used in your Graph Service Client you either use Application permissions defined in your App Registration or the user permissions ANDed with the defined delegated permissions for your app.

So if you use the client secrets you have the application permissions and can access everything that the tenant administrator consented when adding the app to her tenant and is independent from any user.

If you use some user specific login like the interactive browser credential your graph client will act in the name of the authenticated user. With this approach you can access anything the user is allowed to read / write AND the delegated permissions defined in your registered app within the tenant.

In your example you used a client secret. This means, you act in the name of the application and the administrator gave consent to use the right Directory.Read.All. This means you should be able to read all groups by calling '/groups'.

If you want to include all transitive members from all groups, you can do this in one shot, by calling /groups?$expand=transitiveMembers.

Thank you for the detailed explanation, that makes perfect sense.

Since I don’t currently have an admin account (and therefore can’t create an App Registration or grant Directory.Read.All consent), I understand that the client secret flow won’t work in my case.

I’ll try switching to the delegated flow with an interactive browser login using my normal user account, so the app can act under my own permissions.

Just to confirm: with that approach, I’ll only be able to read the groups and users that my account has access to, right?

Once we get an admin account later, I can switch back to the app-only (client credentials) approach with full directory scope.

Thanks again for pointing out /groups?$expand=transitiveMembers, that’s very helpful.

Also, Just to know, is there any other workaround to read the groups from Azure Directory/Entra using C#?

Be aware, that if you use an user account, you still have to define an app id that has to be used and this needs to have the delegated permission to read all groups. In that case you can then read all groups you have access, because these two rights are ANDed.

Reading / writing data from / to Azure / Entra is only possible via the Graph API. The easiest way from C# would be the Graph SDK, but you can also use plain http requests via HttpClient or any library that makes it easier to formulate request / response pairs like RestEase.

But regardless of the used approach, it all boils down to http requests using a token that is retrieved via one of the auth flows.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.