App identities: proxy credentials vs. real Graph credentials
An App Identity is GraphWarden's record of a client application that talks to Microsoft Graph through the proxy. It carries two credential pairs: the proxy pair your app uses to authenticate to GraphWarden, and the real Graph Client ID plus tenant secret that GraphWarden itself uses when calling Graph on your behalf. Your app only ever sees the proxy pair.
Shipped — Credential rotation is a supported flowPrerequisites
The two credential pairs
GraphWarden's zero-knowledge stance turns on this separation. Confusion about which credential does what is the single most common onboarding mistake.
| Credential | Issued by | Held by | Used to |
|---|---|---|---|
| Proxy Client ID | GraphWarden App Admin | Your client application | Identify the caller on POST /proxy/token |
| Proxy Client Secret | GraphWarden App Admin | Your client application (hashed on the proxy) | Authenticate the caller on POST /proxy/token |
| Graph Client ID | Your Azure AD tenant | GraphWarden (in App Admin database) | Impersonate the real Graph App against Microsoft Graph |
| Graph Client Secret | Your Azure AD tenant | Your Azure Key Vault (GraphWarden reads at runtime) | Obtain a Graph token via MSAL client-credentials flow |
Your app embeds only the proxy pair. If your source code or CI environment contains the Graph Client Secret, you have bypassed GraphWarden entirely and the zero-knowledge property does not hold.
Where credentials live
Each credential has one authoritative home. Copies elsewhere are drift.
- Proxy Client ID — issued and stored in the GraphWarden App Admin database (
app_identities.proxy_client_id). Distributed to your client app by whoever provisions the App Identity. Non-secret. - Proxy Client Secret — generated by App Admin at creation time, shown once, then stored only as a SHA-256 hash on each proxy instance (
proxy_client_secret_hash). Regenerate by rotating (see below); the old secret is discarded the moment a new one is issued. - Graph Client ID — copied from your Azure AD app registration into App Admin (
app_identities.real_client_id). Non-secret; Azure AD treats this as a public identifier. - Graph Client Secret — NEVER stored in App Admin or the proxy. Written directly to
microsoft_tenants.key_vault_urlby an operator using the GraphWarden Key Vault helper. The proxy reads it at runtime using Managed Identity (production) or an explicit service principal (development). A secret name oftenant-{tenant_uuid}-identity-{real_client_id}is the convention.
Creating an App Identity
The canonical path is through the GraphWarden App Admin UI. The flow below is the conceptual sequence; the App Admin guide covers the click-by-click steps.
- Register the Graph App in Azure AD — create the Azure AD application, grant it the application permissions you want GraphWarden to broker, and obtain the real
client_idplus a fresh client secret. - Write the Graph secret to Key Vault — use the Key Vault helper to store the secret at the convention-named secret. GraphWarden never sees the cleartext.
- Create the App Identity in App Admin — supply the
real_client_id, pick the ruleset to bind, and submit. App Admin generates theproxy_client_idand a freshproxy_client_secret, shows the secret ONCE, and records only the hash. - Distribute the proxy pair to your application — store the proxy credentials in your app's secret manager (environment variables, CI secrets, Azure Key Vault for your app, etc.). Ship the values via your existing secret-distribution channel; GraphWarden does not re-surface them.
Rotating credentials
Both credential pairs rotate independently.
Proxy pair — in App Admin, open the App Identity and click Rotate Secret. A new secret is generated, the new hash replaces the old one on the next sync cycle (typically seconds), and the old cleartext is destroyed. Update your application's configuration to the new secret before the sync runs to avoid a token-request gap, or accept a brief 401 window.
Graph pair — rotate the Graph Client Secret in Azure AD first, then write the new secret to the same Key Vault entry. GraphWarden picks it up on the next MSAL token request (expired tokens are re-acquired transparently). The real_client_id rarely changes; if it does, update App Admin and re-provision the Key Vault entry under the new convention name.
Troubleshooting
401 on /proxy/token immediately after a rotation — the proxy instance has not yet resynced the new hash. Wait one sync cycle (RuleSync:IntervalSeconds, default 60 seconds) or hit the admin API to force a sync.
Graph returns 401 AADSTS7000215 through the proxy — the Graph Client Secret in Key Vault is expired or wrong. Confirm the entry exists at tenant-{tenant_uuid}-identity-{real_client_id} and that the value matches the secret shown in Azure AD.
Proxy logs KeyNotFound for a Key Vault secret — the proxy's Managed Identity lacks get permission on that specific secret. Grant get (NOT list or set) on the secret in Key Vault access policies or RBAC.
Two App Identities for the same Graph App — supported, and often useful when one app uses distinct rulesets for distinct workflows (e.g., a read-only reporting job and an admin-write job). Each App Identity carries its own proxy pair; the Graph App can be shared.
Last reviewed: