|
| 1 | +# Microsoft.Identity.Web.AgentIdentities |
| 2 | + |
| 3 | +## Overview |
| 4 | + |
| 5 | +The Microsoft.Identity.Web.AgentIdentities NuGet package provides support for Agent Identities in Microsoft Entra ID. It enables applications to securely authenticate and acquire tokens for agent applications, agent identities, and agent user identities, which is useful for autonomous agents, interactive agents acting on behalf of their user, and agents having their own user identity. |
| 6 | + |
| 7 | +This package is part of the [Microsoft.Identity.Web](https://github.com/AzureAD/microsoft-identity-web) suite of libraries and was introduced in version 3.10.0. |
| 8 | + |
| 9 | +## Key Concepts |
| 10 | + |
| 11 | +### Agent Applications |
| 12 | + |
| 13 | +An agent application has a special application registration in Microsoft Entra ID that has permissions to act on behalf of Agent identities or Agent User identities, through Federated Identity Credentials (FIC). It's represented by its application ID (Agent Application Client ID). The agent application is configured with credentials (typically FIC+MSI or client certificates) and permissions to acquire tokens for itself to call graph. This is the app that you develop. It's a confidential client application, usually a web API. The only permissions it can have are maintain (create / delete) Agent Identities (using the Microsoft Graph) |
| 14 | + |
| 15 | +### Agent Identity |
| 16 | + |
| 17 | +An agent identity is a special service principal in Microsoft Entra ID. It represents an identity that the agent application created and is authorized to impersonate. It doesn't have credentials on its own. The agent application can acquire tokens on behalf of the agent identity provided the user or tenant admin consented for the agent identity to the corresponding scopes. Autonomous agents acquire app tokens on behalf of the agent identity. Interactive agents called with a user token acquire user tokens on behalf of the agent identity. |
| 18 | + |
| 19 | +### Agent User Identity |
| 20 | + |
| 21 | +An agent user identity is an Agent identity that can also act as a user (think of an agent identity that would have its own mailbox, or would report to you in the directory). An agent application can acquire a token on behalf of an agent user identity. |
| 22 | + |
| 23 | +### Federated Identity Credentials (FIC) |
| 24 | + |
| 25 | +FIC is a trust mechanism in Microsoft Entra ID that enables applications to trust each other using OpenID Connect (OIDC) tokens. In the context of agent identities, FICs are used to establish trust between the agent application and agent identities, and agent identities and agent user identities |
| 26 | + |
| 27 | +## Installation |
| 28 | + |
| 29 | +```bash |
| 30 | +dotnet add package Microsoft.Identity.Web.AgentIdentities |
| 31 | +``` |
| 32 | + |
| 33 | +## Usage |
| 34 | + |
| 35 | +### 1. Configure Services |
| 36 | + |
| 37 | +First, register the required services in your application: |
| 38 | + |
| 39 | +```csharp |
| 40 | +// Add the core Identity Web services |
| 41 | +services.AddTokenAcquisition(); |
| 42 | +services.AddInMemoryTokenCaches(); |
| 43 | +services.AddHttpClient(); |
| 44 | + |
| 45 | +// Add Microsoft Graph integration if needed. |
| 46 | +// Requires the Microsoft.Identity.Web.GraphServiceClient package |
| 47 | +services.AddMicrosoftGraph(); |
| 48 | + |
| 49 | +// Add Agent Identities support |
| 50 | +services.AddAgentIdentities(); |
| 51 | +``` |
| 52 | + |
| 53 | +### 2. Configure the Agent Application |
| 54 | + |
| 55 | +Configure your application with the necessary credentials using appsettings.json: |
| 56 | + |
| 57 | +```json |
| 58 | +{ |
| 59 | + "AzureAd": { |
| 60 | + "Instance": "https://login.microsoftonline.com/", |
| 61 | + "TenantId": "your-tenant-id", |
| 62 | + "ClientId": "agent-application-client-id", |
| 63 | + |
| 64 | + "ClientCredentials": [ |
| 65 | + { |
| 66 | + "SourceType": "StoreWithDistinguishedName", |
| 67 | + "CertificateStorePath": "LocalMachine/My", |
| 68 | + "CertificateDistinguishedName": "CN=YourCertificateName" |
| 69 | + } |
| 70 | + |
| 71 | + // Or for Federation Identity Credential with Managed Identity: |
| 72 | + // { |
| 73 | + // "SourceType": "SignedAssertionFromManagedIdentity", |
| 74 | + // "ManagedIdentityClientId": "managed-identity-client-id" // Omit for system-assigned |
| 75 | + // } |
| 76 | + ] |
| 77 | + } |
| 78 | +} |
| 79 | +``` |
| 80 | + |
| 81 | +Or, if you prefer, configure programmatically: |
| 82 | + |
| 83 | +```csharp |
| 84 | +// Configure the information about the agent application |
| 85 | +services.Configure<MicrosoftIdentityApplicationOptions>( |
| 86 | + options => |
| 87 | + { |
| 88 | + options.Instance = "https://login.microsoftonline.com/"; |
| 89 | + options.TenantId = "your-tenant-id"; |
| 90 | + options.ClientId = "agent-application-client-id"; |
| 91 | + options.ClientCredentials = [ |
| 92 | + CertificateDescription.FromStoreWithDistinguishedName( |
| 93 | + "CN=YourCertificateName", StoreLocation.LocalMachine, StoreName.My) |
| 94 | + ]; |
| 95 | + }); |
| 96 | +``` |
| 97 | + |
| 98 | +See https://aka.ms/ms-id-web/credential-description for all the ways to express credentials. |
| 99 | + |
| 100 | +On ASP.NET Core, use the override of services.Configure taking an authentication shceme. |
| 101 | + |
| 102 | +### 3. Use Agent Identities |
| 103 | + |
| 104 | +#### Agent Identity |
| 105 | + |
| 106 | +##### Autonomous agent |
| 107 | + |
| 108 | +For your autonomous agent application to acquire **app** tokens for an agent identity: |
| 109 | + |
| 110 | +```csharp |
| 111 | +// Get the required services from the DI container |
| 112 | +IAuthorizationHeaderProvider authorizationHeaderProvider = |
| 113 | + serviceProvider.GetRequiredService<IAuthorizationHeaderProvider>(); |
| 114 | + |
| 115 | +// Configure options for the agent identity |
| 116 | +string agentIdentity = "agent-identity-guid"; |
| 117 | +var options = new AuthorizationHeaderProviderOptions() |
| 118 | + .WithAgentIdentity(agentIdentity); |
| 119 | + |
| 120 | +// Acquire an access token for the agent identity |
| 121 | +string authHeader = await authorizationHeaderProvider |
| 122 | + .CreateAuthorizationHeaderForAppAsync("https://resource/.default", options); |
| 123 | + |
| 124 | +// The authHeader contains "Bearer " + the access token (or another protocol |
| 125 | +// depending on the options) |
| 126 | +``` |
| 127 | + |
| 128 | +##### Interactive agent |
| 129 | + |
| 130 | +For your interactive agent application to acquire **user** tokens for an agent identity on behalf of the user calling the web API: |
| 131 | + |
| 132 | +```csharp |
| 133 | +// Get the required services from the DI container |
| 134 | +IAuthorizationHeaderProvider authorizationHeaderProvider = |
| 135 | + serviceProvider.GetRequiredService<IAuthorizationHeaderProvider>(); |
| 136 | + |
| 137 | +// Configure options for the agent identity |
| 138 | +string agentIdentity = "agent-identity-guid"; |
| 139 | +var options = new AuthorizationHeaderProviderOptions() |
| 140 | + .WithAgentIdentity(agentIdentity); |
| 141 | + |
| 142 | +// Acquire an access token for the agent identity |
| 143 | +string authHeader = await authorizationHeaderProvider |
| 144 | + .CreateAuthorizationHeaderForAppAsync(["https://resource/.default"], options); |
| 145 | + |
| 146 | +// The authHeader contains "Bearer " + the access token (or another protocol |
| 147 | +// depending on the options) |
| 148 | +
|
| 149 | + |
| 150 | +#### Agent User Identity |
| 151 | + |
| 152 | +For your agent application to acquire tokens on behalf of a agent user identity: |
| 153 | + |
| 154 | +```csharp |
| 155 | +// Get the required services |
| 156 | +IAuthorizationHeaderProvider authorizationHeaderProvider = |
| 157 | + serviceProvider.GetRequiredService<IAuthorizationHeaderProvider>(); |
| 158 | + |
| 159 | +// Configure options for the agent user identity |
| 160 | +string agentIdentity = "agent-identity-client-id"; |
| 161 | +string userUpn = "user@contoso.com"; |
| 162 | +var options = new AuthorizationHeaderProviderOptions() |
| 163 | + .WithAgentUserIdentity(agentIdentity, userUpn); |
| 164 | + |
| 165 | +// Create a ClaimsPrincipal to enable token caching |
| 166 | +ClaimsPrincipal user = new ClaimsPrincipal(); |
| 167 | + |
| 168 | +// Acquire a user token |
| 169 | +string authHeader = await authorizationHeaderProvider |
| 170 | + .CreateAuthorizationHeaderForUserAsync( |
| 171 | + scopes: ["https://graph.microsoft.com/.default"], |
| 172 | + options: options, |
| 173 | + user: user); |
| 174 | + |
| 175 | +// The user object now has claims including uid and utid. If you use it |
| 176 | +// in another call it will use the cached token. |
| 177 | +``` |
| 178 | + |
| 179 | +### 4. Microsoft Graph Integration |
| 180 | + |
| 181 | +#### Using Agent Identity with Microsoft Graph: |
| 182 | + |
| 183 | +```csharp |
| 184 | +// Get the GraphServiceClient |
| 185 | +GraphServiceClient graphServiceClient = serviceProvider.GetRequiredService<GraphServiceClient>(); |
| 186 | + |
| 187 | +// Call Microsoft Graph APIs with the agent identity |
| 188 | +var applications = await graphServiceClient.Applications |
| 189 | + .GetAsync(r => r.Options.WithAuthenticationOptions(options => |
| 190 | + { |
| 191 | + options.WithAgentIdentity(agentIdentity); |
| 192 | + options.RequestAppToken = true; |
| 193 | + })); |
| 194 | +``` |
| 195 | + |
| 196 | +#### Using Agent User Identity with Microsoft Graph: |
| 197 | + |
| 198 | +```csharp |
| 199 | +// Get the GraphServiceClient |
| 200 | +GraphServiceClient graphServiceClient = serviceProvider.GetRequiredService<GraphServiceClient>(); |
| 201 | + |
| 202 | +// Call Microsoft Graph APIs with the agent user identity |
| 203 | +var me = await graphServiceClient.Me |
| 204 | + .GetAsync(r => r.Options.WithAuthenticationOptions(options => |
| 205 | + options.WithAgentUserIdentity(agentIdentity, userUpn))); |
| 206 | +``` |
| 207 | + |
| 208 | +### 5. Downstream API Integration |
| 209 | + |
| 210 | +To call other APIs using the IDownstreamApi abstraction: |
| 211 | + |
| 212 | +```csharp |
| 213 | +// Get the IDownstreamApi service |
| 214 | +IDownstreamApi downstreamApi = serviceProvider.GetRequiredService<IDownstreamApi>(); |
| 215 | + |
| 216 | +// Call API with agent identity |
| 217 | +var response = await downstreamApi.GetForAppAsync<string>( |
| 218 | + "MyApi", |
| 219 | + options => options.WithAgentIdentity(agentIdentity)); |
| 220 | + |
| 221 | +// Call API with agent user identity |
| 222 | +var userResponse = await downstreamApi.GetForUserAsync<string>( |
| 223 | + "MyApi", |
| 224 | + options => options.WithAgentUserIdentity(agentIdentity, userUpn)); |
| 225 | +``` |
| 226 | + |
| 227 | +## Prerequisites |
| 228 | + |
| 229 | +### Microsoft Entra ID Configuration |
| 230 | + |
| 231 | +1. **Agent Application Configuration**: |
| 232 | + - Register an agent application with the graph SDK |
| 233 | + - Add client credentials for the agent application |
| 234 | + - Grant appropriate API permissions, such as Application.ReadWrite.All to create agent identities |
| 235 | + - Example configuration in JSON: |
| 236 | + ```json |
| 237 | + { |
| 238 | + "AzureAd": { |
| 239 | + "Instance": "https://login.microsoftonline.com/", |
| 240 | + "TenantId": "your-tenant-id", |
| 241 | + "ClientId": "agent-application-id", |
| 242 | + "ClientCredentials": [ |
| 243 | + { |
| 244 | + "SourceType": "StoreWithDistinguishedName", |
| 245 | + "CertificateStorePath": "LocalMachine/My", |
| 246 | + "CertificateDistinguishedName": "CN=YourCertName" |
| 247 | + } |
| 248 | + ] |
| 249 | + } |
| 250 | + } |
| 251 | + ``` |
| 252 | + |
| 253 | +2. **Agent Identity Configuration**: |
| 254 | + - Have the agent create an agent identity |
| 255 | + - Grant appropriate API permissions based on what your agent identity needs to do |
| 256 | + |
| 257 | +3. **User Permission**: |
| 258 | + - For agent user identity scenarios, ensure appropriate user permissions are configured. |
| 259 | + |
| 260 | +## How It Works |
| 261 | + |
| 262 | +Under the hood, the Microsoft.Identity.Web.AgentIdentities package: |
| 263 | + |
| 264 | +1. Uses Federated Identity Credentials (FIC) to establish trust between the agent application and agent identity and between the agent identity and the agent user identity. |
| 265 | +2. Acquires FIC tokens using the `GetFicTokenAsync` method |
| 266 | +3. Uses the FIC tokens to authenticate as the agent identity |
| 267 | +4. For agent user identities, it leverages MSAL extensions to perform user token acquisition |
| 268 | + |
| 269 | +## Troubleshooting |
| 270 | + |
| 271 | +### Common Issues |
| 272 | + |
| 273 | +1. **Missing FIC Configuration**: Ensure Federated Identity Credentials are properly configured in Microsoft Entra ID between the agent application and agent identity. |
| 274 | + |
| 275 | +2. **Permission Issues**: Verify the agent application has sufficient permissions to manage agent identities and that the agent identities have enough permissions to call the downstream APIs. |
| 276 | + |
| 277 | +3. **Certificate Problems**: If you use a client certificate, make sure the certificate is registered in the app registration, and properly installed and accessible by the code of the agent application. |
| 278 | + |
| 279 | +4. **Token Acquisition Failures**: Enable logging to diagnose token acquisition failures: |
| 280 | + ```csharp |
| 281 | + services.AddLogging(builder => { |
| 282 | + builder.AddConsole(); |
| 283 | + builder.SetMinimumLevel(LogLevel.Debug); |
| 284 | + }); |
| 285 | + ``` |
| 286 | + |
| 287 | +## Resources |
| 288 | + |
| 289 | +- [Microsoft Entra ID documentation](https://docs.microsoft.com/en-us/azure/active-directory/) |
| 290 | +- [Microsoft Identity Web documentation](https://github.com/AzureAD/microsoft-identity-web/wiki) |
| 291 | +- [Workload Identity Federation](https://docs.microsoft.com/en-us/azure/active-directory/develop/workload-identity-federation) |
| 292 | +- [Microsoft Graph SDK documentation](https://docs.microsoft.com/en-us/graph/sdks/sdks-overview) |
0 commit comments