Hardcoding group IDs in your config is a quick way to ship broken access control three months later. A user moves teams, the group ID rotates, and your roles stop matching.
This walkthrough shows how to read AD groups at runtime using the Microsoft Graph API instead of maintaining a brittle config list. You'll see two authentication paths: client credentials with a client secret, and Managed Service Identity where Azure handles the token lifecycle. Both return the same Graph client—just different ways to get the token.
Why Hardcoded Group IDs Break
When you paste AD group GUIDs into appsettings.json, the app trusts that list. If someone renames a group, deletes it, or a new one takes its place, your authorization policies still resolve against the old IDs. Permissions drift silently until someone can't log in.
Microsoft Graph lets your code ask Azure AD for the current list of groups by name at request time. Changes on the directory side automatically propagate—no config redeploy when someone moves teams.
Setting Up the AD App for Client Credentials
For the client credentials flow, register an Azure AD application in the Azure portal. Under Certificates and Secrets, create a new client secret. Under API permissions, grant the app Group.Read.All (admin consent required for tenant-wide reads).
Construct a GraphServiceClient using the client ID, tenant domain, and client secret. The reference example uses AuthenticationContext to fetch a token from login.microsoftonline.com and wires it into the client via a DelegateAuthenticationProvider.
Skip the Secret With Managed Identity
Storing client secrets means rotation, storage, and leakage risk. Azure's Managed Identity feature removes that operational burden.
Turn on Identity for the Azure Web App in the portal. Azure creates a service principal automatically. Your code no longer needs client ID or secret because the platform issues tokens directly.
One catch: granting the managed identity access to Graph API isn't exposed in the portal UI. A short PowerShell script assigns Group.Read.All using New-AzureADServiceAppRoleAssignment. The script filters the Microsoft Graph AppId (00000003-0000-0000-c000-000000000000) for the Group.Read.All role entry and assigns it to the managed identity's service principal.
After that, AzureServiceTokenProvider fetches a token at runtime. The provider tries MSI first, then falls back to other credentials if running outside Azure. Note: the SDK team now recommends DefaultAzureCredential, which unifies MSI, Azure CLI, Visual Studio, and Integrated Windows Authentication in one class.
Querying Groups and Plugging Them Into Authorization
With GraphServiceClient ready, call client.Groups.Request().GetAsync() to retrieve groups. Handle pagination with NextPageRequest. Map friendly group names to internal roles rather than to GUIDs—if a group's ID changes, the lookup still resolves to the right name.
Auth Path Comparison
| Client Credentials | Managed Identity | |
|---|---|---|
| Secret management | Manual (you create, store, rotate) | None (Azure handles) |
| Portal permission assignment | Yes | No (requires PowerShell) |
| Works outside Azure | Yes | No (falls back to local creds) |
| Best for | Cross-cloud, hybrid | Azure-hosted apps |
Who Should Care
- Developers maintaining .NET Core apps with RBAC**: Eliminate the config-redeploy cycle when teams change.
- DevOps managing secret rotation**: Managed Identity removes an entire credential surface.
- Architects designing authorization**: Graph-backed role resolution scales better than config lists.
Bottom Line
Reading Azure AD groups through Graph API is the right move for apps with non-trivial role logic. Hardcoded IDs become a maintenance burden fast. The implementation is a few dozen lines of C# once the auth pipeline is sorted, and the payoff compounds every time someone changes teams.
What to watch next: DefaultAzureCredential replacing AzureServiceTokenProvider, and whether portal UI support arrives for MSI permission assignment.
Key takeaways
- Replace hardcoded AD group IDs with runtime Graph API lookups.
- Managed Identity removes secret management for Azure-hosted apps.
- MSI permission assignment still requires PowerShell.
- Map friendly group names to internal roles rather than to GUIDs.
- DefaultAzureCredential is the recommended credential class going forward.
Frequently asked questions
Do I still need an AD app registration if I use Managed Identity?
You register the app for hosting, but the managed identity itself handles token acquisition. No client secret storage needed for MSI auth.
What's the difference between AzureServiceTokenProvider and DefaultAzureCredential?
They serve the same purpose, but DefaultAzureCredential is the newer unified class. New code should use it; AzureServiceTokenProvider still works but is being phased out.
Why does permission assignment for Managed Identity require PowerShell?
The Azure portal UI doesn't expose app role assignment for managed identities. PowerShell fills the gap. This may migrate to the portal in future updates.
Can I use Graph API without admin consent?
For your own user profile or owned resources, yes. Reading directory-wide groups typically requires admin consent for Group.Read.All.
Does this work outside Azure?
Not with Managed Identity alone. Outside Azure, AzureServiceTokenProvider and DefaultAzureCredential fall back to Visual Studio, Azure CLI, or Integrated Windows Authentication.