Home / Azure

AzureRunbookIntermediate

Sev1: AADSTS7000222 — expired service principal secret took down apps and pipelines

Restore applications, pipelines and Terraform runs that fail because an app registration's client secret or certificate expired. Find every expiring credential, rotate without a second outage and move to managed identities.

Deepak Bhardwaj2 min read

Applies toMicrosoft Entra ID app registrations, Azure DevOps and GitHub service connections, Azure CLI 2.50+

Symptoms

  • AADSTS7000222: The provided client secret keys for app '<id>' are expired.
  • AADSTS7000215: Invalid client secret provided (wrong value after a partial rotation).
  • Azure DevOps service connections, ADF linked services, Terraform and scripts all fail at once.

1. Find the app and its credentials

az ad app show --id <appId> --query "{name:displayName, secrets:passwordCredentials[].{hint:hint, end:endDateTime, id:keyId}, certs:keyCredentials[].{end:endDateTime, id:keyId}}" -o json

Find which callers used it recently:

AADServicePrincipalSignInLogs
| where TimeGenerated > ago(1d)
| where AppId == "<appId>"
| summarize count() by ResultType, IPAddress, ResourceDisplayName

2. Add a new secret without removing the old one

az ad app credential reset --id <appId> --append --display-name "rotated-2026-10-24" --years 1 --query password -o tsv

--append keeps existing credentials. Without it, the command removes them, which breaks anything that still uses a valid older secret.

Warning

The secret value is shown once. Put it straight into Key Vault, not a chat window or ticket.

az keyvault secret set --vault-name kv-platform --name sp-deploy-secret --value "<new-secret>"

3. Update every consumer

Consumer Where to update
Azure DevOps service connection Project settings → Service connections → Edit → secret
GitHub Actions Repository or environment secret AZURE_CLIENT_SECRET
ADF / Synapse linked service Prefer a Key Vault reference; otherwise edit and publish
App Service / Functions App setting or Key Vault reference, then restart
Terraform ARM_CLIENT_SECRET in the pipeline variable group

Test one consumer end to end before updating the rest.

4. Remove the expired credential

az ad app credential delete --id <appId> --key-id <old-keyId>

5. Find what expires next

az ad app list --all --query "[].{name:displayName, appId:appId, ends:passwordCredentials[].endDateTime}" -o json > apps.json
$apps = Get-Content apps.json | ConvertFrom-Json
$apps | ForEach-Object {
  foreach ($e in $_.ends) { if ([datetime]$e -lt (Get-Date).AddDays(30)) { "{0}  {1}  {2}" -f $_.name, $_.appId, $e } }
}

Prevent it next time

  • Move Azure-hosted workloads to managed identities — no secret to expire.
  • Use workload identity federation for GitHub Actions, Azure DevOps and Terraform Cloud.
  • Where secrets remain, alert 30 days before expiry and keep values only in Key Vault.
  • Record an owner for every app registration.