Skip to content

Commit bd2eed1

Browse files
docs: add call-site snippet, naming note, and request-level rationale
- Clarify that the new WithClientClaims(string) request-level API coexists without conflict with the existing obsolete app-level WithClientClaims (X509Certificate2, IDictionary) — different classes, different signatures - Add NSP SDK call-site code snippet showing claims sourced at request time, making the request-level design concrete and demonstrating why app-level placement would not support dynamic enforcement-mode changes - Add explanation of why per-request placement is correct: enforcement mode changes produce new claims; request-level avoids needing to recreate the app Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent b609cf7 commit bd2eed1

1 file changed

Lines changed: 24 additions & 0 deletions

File tree

docs/nsp_claims_design.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ MSIv2 uses a different protocol from MSIv1. It acquires an mTLS binding certific
4545

4646
Add `WithClientClaims(string claimsJson)` across the MSI, client credentials, and FIC request builders.
4747

48+
### Naming note: coexistence with the existing obsolete `WithClientClaims`
49+
50+
`ConfidentialClientApplicationBuilder` already has an **obsolete, app-level** `WithClientClaims(X509Certificate2, IDictionary<string,string>, ...)` that signs extra claims into the client assertion JWT. The new API described here is a **request-level** method on `AcquireTokenForManagedIdentityParameterBuilder` and `AcquireTokenForClientParameterBuilder` that takes a JSON string. The two APIs are on different classes with different signatures and coexist without ambiguity. The obsolete app-level overload remains for backward compatibility and is unaffected by this change.
51+
4852
### Distinction from `WithClaims()`
4953

5054
| API | Who originates | Cache behavior | Use case |
@@ -78,6 +82,26 @@ If dynamic claims truly cannot be avoided, the following options are available (
7882

7983
For the NSP use case specifically, the claims represent a network security perimeter identifier, which is stable per workload deployment. Dynamic values are not expected to be an issue here.
8084

85+
### Why the API is request-level, not app-level
86+
87+
`WithClientClaims` is intentionally placed on the request builder, not the application builder, to support scenarios where claims change at runtime — for example, when an admin toggles NSP enforcement mode, the NSP SDK vends updated claims and the workload needs MSAL to acquire a new token scoped to those claims. If claims were baked into the application object, the caller would have to destroy and recreate the `ManagedIdentityApplication` on every enforcement change.
88+
89+
Typical NSP usage:
90+
91+
```csharp
92+
// nspContext is updated by the NSP SDK when enforcement mode changes.
93+
// Each distinct claims value maps to its own cache entry.
94+
string currentNspClaims = nspContext.GetCurrentClaimsJson();
95+
96+
AuthenticationResult result = await miApp
97+
.AcquireTokenForManagedIdentity("https://management.azure.com/")
98+
.WithClientClaims(currentNspClaims)
99+
.ExecuteAsync(cancellationToken)
100+
.ConfigureAwait(false);
101+
```
102+
103+
The per-request placement means the caller doesn't need to recreate the app when claims update — a new request with new claims produces a new cache entry automatically.
104+
81105
## Open Questions
82106

83107
1. **API shape**: Is `WithClientClaims` the right name and signature for all teams involved?

0 commit comments

Comments
 (0)