Generate a Microsoft identity principal for local development
Need to exercise different users and roles before wiring production login? The Microsoft identity header adapter can construct a principal from development HTTP headers. This is identity simulation, not token validation.
Understand the trust boundary first
Section titled “Understand the trust boundary first”x-ms-client-principal is Base64-encoded JSON — an unsigned assertion, not a signed bearer token. Arc’s header handlers decode it and construct claims; they do not validate a signature, issuer, or audience. Header presence and valid JSON do not prove who sent it.
Use manually supplied headers only on an isolated, loopback-bound development host. In production, either configure a real token/cookie authentication scheme or accept these assertions only from a trusted authenticated ingress. That ingress must strip and replace all incoming identity headers, and the backend must not be reachable through a bypass route. An arbitrary browser or proxy sending these headers is not trustworthy.
The authorization tutorial shows the ASP.NET registration and middleware placement for a Development-only fixture. The lightweight host authentication is a different setup; do not mix their APIs.
Construct the assertion
Section titled “Construct the assertion”The adapter expects all three headers:
| Header | Content |
|---|---|
x-ms-client-principal | Base64 JSON following the client principal shape |
x-ms-client-principal-id | The selected user’s stable identifier |
x-ms-client-principal-name | The selected user’s display name or email |
Save this synthetic fixture as principal.json in your local application workspace:
{ "identityProvider": "aad", "userId": "e7f664ca-4ecc-45be-84cf-74b6240d049a", "userDetails": "jane.doe@contoso.com", "userRoles": ["anonymous", "authenticated", "Librarian"], "claims": [ { "typ": "preferred_username", "val": "jane.doe@contoso.com" }, { "typ": "name", "val": "Jane Doe" }, { "typ": "given_name", "val": "Jane" }, { "typ": "family_name", "val": "Doe" }, { "typ": "oid", "val": "e7f664ca-4ecc-45be-84cf-74b6240d049a" } ]}userRoles is mapped to role claims by the header adapter. Include Librarian for the successful tutorial case; remove it for an authenticated-but-not-authorized case. A role field returned by IProvideIdentityDetails would not have the same effect.
Encode locally, keeping the result on one line:
python3 -c 'import base64,pathlib; print(base64.b64encode(pathlib.Path("principal.json").read_bytes()).decode())'A local editor’s Base64 action is another option. Do not submit real identity payloads to an online encoder. Base64 provides neither confidentiality nor authenticity.
Configure ModHeader narrowly
Section titled “Configure ModHeader narrowly”In ModHeader, create a development-only profile and add an include URL filter before enabling it. For the tutorial Vite server, use ^http://localhost:5173/.*$. Add a separate ^http://localhost:5000/.*$ only when testing that backend directly. If you use a different local port, update the filter; never select all requests.
Set:
x-ms-client-principal-id:e7f664ca-4ecc-45be-84cf-74b6240d049ax-ms-client-principal-name:jane.doe@contoso.comx-ms-client-principal: the one-line Base64 output above

Use separate filtered profiles for different synthetic users. Confirm in browser developer tools that headers are sent only to your intended localhost application.
Verify the distinct behaviors
Section titled “Verify the distinct behaviors”- No headers: protected operations reject an unauthenticated caller.
- Valid fixture without
Librarian: authentication succeeds but role-protected operations reject access. - Fixture with
Librarian: role-protected operations can execute, subject to their other checks. - Identity-details provider returning
IsUserAuthorized: false:/.cratis/merejects that identity result. This does not replace operation authorization.
These checks test the adapter and your authorization configuration, not production token verification. For production, independently test ingress header replacement, blocked direct backend access, and the real authentication scheme. See identity and access for how claims, details, operation permissions, and tenant membership differ.