Skip to content

Commit aa275fa

Browse files
gladjohnGladwinJohnson
authored andcommitted
Update managed_identity_capabilities_devex.md
1 parent f4a843c commit aa275fa

File tree

1 file changed

+29
-66
lines changed

1 file changed

+29
-66
lines changed
Lines changed: 29 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,34 @@
1-
# Using **ClientCapabilities** (`cp1`) with **Managed Identity** and **Downstream APIs**
1+
# Microsoft.Identity.Web – Claims & Client Capabilities Mini‑Spec (Managed Identity)
22

33
## Why ClientCapabilities (cp1)?
44

5-
Adding the `cp1` client‑capability tells Azure AD your service can handle Continuous Access Evaluation (CAE) claims challenges. Tokens will include an extra xms_cc claim, allowing near‑realtime revocation.
5+
Adding the `cp1` client‑capability tells Microsoft Entra ID your service can handle Continuous Access Evaluation (CAE) claims challenges. Tokens will include an extra xms_cc claim, allowing near‑realtime revocation.
66

7-
## Purpose
7+
## Overview
88

9-
This guide shows how to declare the cp1 client capability (Continuous Access Evaluation)
10-
in a .NET service that authenticates with Managed Identity and calls
11-
resources through Microsoft.Identity.Web’s Downstream API helpers. You’ll learn
12-
how to configure appsettings.json, acquire a CAE‑ready token (xms_cc=cp1),
13-
and optionally invoke Azure Key Vault — all without secrets or certificates.
9+
cp1 signals to Microsoft Entra ID that a workload identity can handle Continuous Access Evaluation (CAE) claims challenges. When a token includes the extra xms_cc claim, Azure can revoke the token (or demand additional claims) in near‑realtime.
1410

15-
## Prerequisites
11+
This spec adds declarative cp1 and claims challenge auto‑handling to Managed Identity flows in Microsoft.Identity.Web (Id.Web). The goal is zero‑touch for most developers: a single configuration knob at startup, automatic 401/claims recovery at runtime.
1612

17-
| Requirement | Notes |
18-
|-------------------------------------------|-----------------------------------------------------------|
19-
| .NET SDK | **8.0** or newer |
20-
| Microsoft.Identity.Web | **latest** |
21-
| Microsoft.Identity.Abstractions | **latest** |
22-
| Azure resource with Managed Identity | VM, App Service, Functions, Container Apps, etc. |
23-
| Key Vault permission | MI needs **Get Secret** on the vault |
13+
## Typical Flow   (MI + Downstream API)
2414

25-
> **Tip** — For **user-assigned** MI, note the **Client ID** (GUID). Leave it blank for **system-assigned** MI.
15+
- MI token request – Id.Web sends xms_cc=cp1 at app creation.
16+
- Access granted – Downstream API returns 200.
17+
- Policy change – Token later revoked; next call to Downstream API gets 401 + claims.
18+
- Transparent recovery – Id.Web detects challenge ⇒ forwards claims body, acquires fresh token, retries once.
2619

27-
## Specification: Configuration Layers
20+
_app developer does not need to handle claims, downstream api takes care of this_
2821

29-
| Layer | JSON path / property | Examples | Lifespan | Rationale |
30-
|------------------|-----------------------------------------------------------|-----------------------------------------------------------------------------------------------------------|---------------------------|-------------------------------------------------------------------------------------------------------------|
31-
| **App-level** | `AzureAd` root → `ClientCapabilities` | `ClientCapabilities: [ "cp1" ]`<br>`Instance`, `TenantId`, credentials | **Process-wide** — set once at startup | MSAL builds the client object **once**; everything here is stamped onto **every** token request. |
32-
| **Request-level**| `AcquireTokenOptions` (inside each *DownstreamApi* entry, or passed programmatically) |`ManagedIdentity.UserAssignedClientId`<br>• `Claims` (CAE challenges)<br>• `ForceRefresh`<br>• `UseMtlsPoP` | **Per token call** | These knobs can differ by resource or retry and therefore belong in the per-call options object. |
22+
## Design Goals
3323

34-
### Why `cp1` stays at the App-level
35-
* **Identity of the client** – signals a *capability of the app*, not an individual request.
24+
| # | Goal | Success Metric |
25+
|-----|--------------------------------------------------------------|----------------------------------------------------------|
26+
| G1 | Transparent CAE retry with cache-bypass on 401 claims challenge. | Secret or Graph call recovers without developer code. |
27+
| G2 | Declarative client capabilities via configuration. | Single place to add `cp1`; all MI calls include it. |
28+
29+
## 5 · Public API Impact
30+
31+
no changes to the public api.
3632

3733
## Configuration
3834

@@ -42,6 +38,7 @@ and optionally invoke Azure Key Vault — all without secrets or certificates.
4238
"ClientCapabilities": [ "cp1" ]
4339
},
4440
41+
// Resource entry (example)
4542
"AzureKeyVault": {
4643
"BaseUrl": "https://<your‑vault>.vault.azure.net/",
4744
"RelativePath": "secrets/<secret-name>?api-version=7.4",
@@ -60,58 +57,24 @@ and optionally invoke Azure Key Vault — all without secrets or certificates.
6057
## Code
6158

6259
```cs
63-
// Copyright (c) Microsoft Corporation. All rights reserved.
64-
// Licensed under the MIT License.
65-
66-
using Microsoft.Extensions.DependencyInjection;
67-
using Microsoft.Extensions.Logging;
68-
using Microsoft.Identity.Abstractions;
69-
using Microsoft.Identity.Web;
70-
using System.Net;
71-
using System.Text.Json;
72-
73-
// ── 1. bootstrap factory (reads appsettings.json automatically) ─────────
74-
var factory = TokenAcquirerFactory.GetDefaultInstance();
75-
76-
// optional console logging
77-
factory.Services.AddLogging(b => b.AddConsole().SetMinimumLevel(LogLevel.Warning));
78-
79-
// ── 2. register the downstream API using the "AzureKeyVault" section ────
60+
// register the downstream API using the "AzureKeyVault" section ────
8061
factory.Services.AddDownstreamApi("AzureKeyVault",
8162
factory.Configuration.GetSection("AzureKeyVault"));
8263
IServiceProvider sp = factory.Build();
8364
IDownstreamApi api = sp.GetRequiredService<IDownstreamApi>();
8465

8566
// ── 3. call the vault (app-token path) ──────────────────────────────────
8667
HttpResponseMessage response = await api.CallApiForAppAsync("AzureKeyVault");
68+
```
8769

88-
if (response.StatusCode != HttpStatusCode.OK)
89-
{
90-
Console.WriteLine($"Vault returned {(int)response.StatusCode} {response.ReasonPhrase}");
91-
return;
92-
}
93-
94-
//Get the secret value from the response
95-
using var doc = JsonDocument.Parse(await response.Content.ReadAsStringAsync());
70+
## Telemetry
9671

97-
// Check if the "value" property exists and is a string
98-
if (doc.RootElement.TryGetProperty("value", out var valueElement) && valueElement.ValueKind == JsonValueKind.String)
99-
{
100-
// Retrieve the secret value but do not print it
101-
string secret = valueElement.GetString()!;
72+
We rely on server side telemetry for the token revocation features.
10273

103-
// Optionally, you can check if the secret is not null or empty
104-
if (!string.IsNullOrEmpty(secret))
105-
{
106-
Console.WriteLine("Secret retrieved successfully (non-null).");
107-
}
108-
else
109-
{
110-
Console.WriteLine("Secret value was empty.");
111-
}
112-
}
113-
```
74+
Server dashboards add MI success‑rate with/without cp1.
11475

11576
## Options as seen in MSAL
11677

117-
![alt text](capab1.png)
78+
![alt text](capab1.png)
79+
80+
### reference - [How to use Continuous Access Evaluation enabled APIs in your applications](https://learn.microsoft.com/en-us/entra/identity-platform/app-resilience-continuous-access-evaluation?tabs=dotnet)

0 commit comments

Comments
 (0)