Skip to content

AADSTS7000222: The provided client secret keys are expired

Short answer: AADSTS7000222 means an app or service principal sent a client secret that has passed its expiry date. It is almost always a missed rotation, not an attack. The security angle is secret hygiene: an expired secret still sitting in config files shows where secrets live. Microsoft recommends managed identities or certificates instead. Hunt it in AADServicePrincipalSignInLogs.

Fix: Developer: create a new credential on the app registration's Certificates and secrets page and update every system that uses it. Admin: find every IP still sending the expired secret, update those systems, then remove the expired secret. Move to a managed identity or certificate where you can. Full steps

At a glance
CodeAADSTS7000222
Microsoft nameInvalidClientSecretExpiredKeysProvided
CategoryApp configuration
TypeFailure
Attack signalLow: usually configuration or user error
Where to lookAADServicePrincipalSignInLogs
Microsoft lookuplogin.microsoftonline.com/error?code=7000222

Microsoft’s description:

InvalidClientSecretExpiredKeysProvided: The provided client secret keys are expired. Create new keys for your app, or consider using certificate credentials for added security

An app tried to get a token with a client secret that was valid once but has passed its end date. The secret itself was right. Nobody replaced it in time.

Two siblings help you tell the cases apart:

  • 7000215: “Invalid client secret is provided.” A secret was sent and it was wrong.
  • 7000218: “The request body must contain the following parameter: ‘client_assertion’ or ‘client_secret’.” No secret or assertion was sent at all.

Almost never. 7000222 is what a missed rotation looks like: a script, scheduled job or integration still holds a secret that expired. It usually shows up as a sudden outage of that integration.

Pattern Likely meaning
7000222 for one app from your own servers, starting on a specific day The secret expired that day and nobody rotated it. Benign, but the integration is broken.
7000222 from your own servers after you created a new secret You added a new secret but missed one system that still holds the old one.
7000222 for an app from an IP you don’t own Someone outside holds a copy of an old secret for your app. Our interpretation, not a Microsoft statement: the expiry stopped them, but the secret leaked at some point. Find out where it was stored.

The useful security reading is the third row and the inventory it gives you. Every IP that sends an expired secret is a place where that secret was stored. If one of those systems was compromised, read hunting credential reuse after a web-server breach for which other secrets to rotate.

Which apps are failing, and from where:

AADServicePrincipalSignInLogs
| where TimeGenerated > ago(7d)
| where ResultType == "7000222"
| summarize Attempts = count(),
FirstSeen = min(TimeGenerated),
LastSeen = max(TimeGenerated),
KeyIds = make_set(ServicePrincipalCredentialKeyId, 10)
by AppId, ServicePrincipalName, IPAddress
| sort by Attempts desc

Expired-secret attempts from IPs that never had a success for the same app in the last 30 days:

let knownAppIPs =
AADServicePrincipalSignInLogs
| where TimeGenerated > ago(30d)
| where ResultType == "0"
| distinct AppId, IPAddress;
AADServicePrincipalSignInLogs
| where TimeGenerated > ago(7d)
| where ResultType == "7000222"
| join kind=leftanti knownAppIPs on AppId, IPAddress
| summarize Attempts = count(), LastSeen = max(TimeGenerated) by AppId, ServicePrincipalName, IPAddress
| sort by Attempts desc

Check two things in your own workspace before relying on these queries:

  • The Azure Monitor reference for AADServicePrincipalSignInLogs describes ResultType as “Success or Failure”, while the user sign-in tables document it as the numeric error code as a string. Look at a few failed rows and confirm they carry "7000222" and that successes carry "0". If they don’t, filter on ResultSignature instead.
  • Whether ServicePrincipalCredentialKeyId is filled in on an expired-secret failure isn’t documented. If it is, it tells you exactly which secret is still in use, which makes cleanup easy.

A secret used by a confidential client in a delegated (user) flow may surface in the user sign-in tables instead. That is our reading of how the flows work, not a documented statement. If the first query returns nothing but users report the error, search SigninLogs for the same ResultType.

  • 7000222 is a failed credential check, so no policy grants or blocks it. Conditional Access for workload identities can’t fix an expired secret.
  • Microsoft notes that workload identities “Can’t perform multifactor authentication” and “Need to store their credentials or secrets somewhere.” The control that matters is the credential type.
  • Conditional Access for workload identities can add location and risk conditions to single-tenant service principals, which limits where a leaked secret works. It needs Workload Identities Premium licenses.

For developers: create a new credential on the app registration’s Certificates and secrets page and update every system that uses it. Don’t stop at the first system that works again.

For admins:

  1. Use the first query to list every IP still sending the expired secret, and update or retire each of those systems.
  2. Remove the expired secret from the app registration once nothing uses it. Microsoft: “An unused credential on an application can result in a security breach.”
  3. Move away from secrets. Microsoft’s order of preference is a managed identity first, then certificate credentials: “Don’t use password credentials, also known as secrets.” Certificate credentials work “anywhere a client secret could be used”, including the client credentials flow.
  4. Use application management policies to limit secret lifetimes or block new secrets, so the next rotation is planned rather than an outage.
  5. If the second query returns an IP you don’t own, treat every credential that was stored alongside that secret as exposed.

More: 7000216, 7000218

Sources

  1. Microsoft Entra authentication and authorization error codes
  2. Security best practices for application properties
  3. Microsoft identity platform application authentication certificate credentials
  4. Conditional Access for workload identities
  5. AADServicePrincipalSignInLogs table reference (Azure Monitor)