feat(credentials): Microsoft app credentials for Power BI and Azure Data Explorer, with national clouds
Summary
- Microsoft app credentials now mint tokens per resource. The cache key is credential + stored-secret version + audience, and one table maps each service to its audience. Graph services share one token; every other resource gets its own. The secret is decrypted only on a cache miss, inside the shared mint, so a cached token costs one row read.
- New optional
cloudon the credential: Global (default), US Gov GCC High, US Gov DoD, or China (21Vianet). The Entra endpoint, the certificate assertion audience and the save-time Graph check follow the cloud. China signs in atlogin.partner.microsoftonline.cn, the endpoint the Entra national-cloud reference lists and the one legacy inline ADX sign-ins already use. Graph, Power BI and Dataverse services refuse a national-cloud credential with a newcloud_mismatchcode, whose message names the cloud mismatch instead of asking the user to reconnect. A reconnect opens on the credential's stored cloud. The reconnect reads the stored mode and cloud through one per-provider map, with no provider-specific branch. - Power BI accepts a Microsoft app credential next to its delegated connection. Token audience:
https://analysis.windows.net/powerbi/api/.default. Global cloud only. - New
azure_data_explorer_v2, a credential-only block. The token audience is the allowlisted cluster (or resource-override) host. The credential's cloud must match the cluster's cloud, so a national-cloud cluster needs a matching national-cloud credential. The operation re-checks the credential against the run's workspace or organization, as the AWS operation path does. The legacy block keeps its inline fields and is marked legacy.
Not in this PR (design memos):
-
Azure DevOps service principal. The service-principal guide (https://learn.microsoft.com/en-us/azure/devops/integrate/get-started/authentication/service-principal-managed-identity) uses the token scope
https://app.vssps.visualstudio.com/.default, sent as Bearer. Azure DevOps ignores Entra app permissions. The service principal must be added to each organization as a user, with Basic or higher access, and it takes a paid license. Two things block it:- Each service holds one
serviceAccountProviderId(lib/oauth/types.ts), and Azure DevOps already uses it for its PAT credential. Offering an app credential needs either a list-valued provider-id field across pickers, the resolver and the block contract, or a new provider id. - Every Azure DevOps tool hard-codes a
BasicPAT header. Switching to Bearer means passing the credential kind throughcredentialParamsin every tool, which changes their tool schemas.
It needs a product decision on the credential model and a live proof.
- Each service holds one
-
Azure OpenAI via Entra. The Entra guide (https://learn.microsoft.com/en-us/azure/ai-foundry/openai/how-to/managed-identity) uses the data-plane scope
https://ai.azure.com/.default. It requires a custom-subdomain endpoint and the Cognitive Services OpenAI User role. The provider takes an inline API key and a user-supplied endpoint, and model providers have no saved-credential path yet. It needs that model-credential pattern, an endpoint host allowlist (*.openai.azure.com) and a client cache keyed by credential and expiry. -
Planner/Outlook app-only. Graph's
/merequires a signed-in user, and application permissions are not supported there (https://learn.microsoft.com/en-us/graph/api/user-get?view=graph-rest-1.0). These tools call/me. App-only would need a new user or mailbox parameter that switches to/users/{id}, and tenant-wide mailbox scope is a product and security decision.
Product update (if relevant)
- Admins can run Power BI and Azure Data Explorer as an Entra app registration (client secret, certificate, or keyless federated credential), including in US Government and China clouds for ADX. Setup steps are in the Microsoft app credentials and per-integration docs.
Type of Change
- Bug fix
- New feature
- Breaking change
- Documentation
- Other: ___________
Testing
- Unit:
- Per-audience cache separation; a cached token is served without decrypting; the ADX cluster key includes the resource's clouds.
- National-cloud endpoints and assertion audience;
cloud_mismatchrefusals for Graph, Dataverse, Power BI and ADX. - The reconnect returns the stored mode and cloud.
- ADX operation tests: runs with no inline secret, ignores inline sign-in fields, takes the audience from the override host, refuses a cluster in another cloud (400) before any request, refuses a credential from another workspace before decrypting, refuses a non-allowlisted host before decrypting, does not echo Entra's error detail, keeps the legacy inline path.
- Integration (real Postgres): Power BI run and selector with a persisted app credential.
- Generated artifacts, block-registry check (saved-credential contract, sunset replacedBy) and targeted audits pass locally. Full type-check and audits are left to CI.
- Please review:
- Backward compatibility: global credentials store no
cloudfield, old workers fail closed on a national-cloud secret, and legacy inline ADX authorities are unchanged. - ADX audience derivation and owner-scope re-check in
requestAzureDataExplorerAsApp.
- Backward compatibility: global credentials store no
Checklist
- Code follows project style guidelines
- Self-reviewed my changes
- Tests added/updated and passing
- No new warnings introduced
- I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)