An Entra app registration's client secret expires or gets rotated, and an integration that depends on it stops authenticating with AADSTS7000222 or AADSTS7000215. Entra lets an application hold more than one password credential at a time, so a rotation never needs a gap: add a new secret, move the workload, prove from the sign-in logs that the old secret's key ID has gone quiet, then remove it. This guide gives the Microsoft Graph calls and PowerShell for each step, the sign-in log fields that prove which secret a workload used, and the rollback. It is for identity and platform engineers who own app registrations that cannot yet move to certificates, managed identities or federated credentials.
This is an independent guide from NHI Mgmt Group, based on Microsoft Learn documentation as of November 2026. It is not sponsored or reviewed by Microsoft. Some properties used here are documented on the Microsoft Graph beta endpoint, which Microsoft says can change; confirm against current documentation.
Key takeaways
- Add before you remove.
addPasswordcreates a second secret alongside the first; both work until you callremovePasswordon the oldkeyId. - The key ID is the thread through the whole job. Each secret has a
keyId; service principal sign-ins recordservicePrincipalCredentialKeyId, so you can see exactly which secret each workload used. - The value is shown once.
secretTextcomes back only in the creation response; send it straight to Key Vault or the consumer's secret store. - Short lifetimes need automation. The Graph default end date is two years; a shorter lifetime is safer only if a pipeline rotates it, otherwise it just schedules the next outage.
- Every rotation is a migration opportunity. Microsoft recommends certificates over secrets, and managed identities and federated credentials remove the secret entirely.
When you need this
- Expiry is approaching: the Entra recommendation Renew expiring application credentials (Graph name
applicationCredentialExpiry, in preview) lists app registration credentials expiring in the next 30 days. To build the full list yourself, follow How to find expiring app secrets and certificates in Entra ID. - A person or supplier with the value has left: anyone who once copied the secret can still use it until it is removed.
- Policy age: your standard sets a maximum lifetime shorter than the secret's end date.
- Not for a confirmed leak: if the secret is in a public repository or is being used from unknown addresses, remove it now and accept the outage. Application credentials are a prized target: in the Microsoft Midnight Blizzard Breach 2024 a legacy test OAuth application was part of the route into executive mailboxes. Follow the Leaked Credential Response Playbook.
Before you start
| Check | Why it matters | How |
|---|---|---|
| You have the application's object ID and app ID | addPassword accepts either /applications/{id} (object ID) or /applications(appId='{appId}') | App registrations overview page, or Get-MgApplication |
| You know where the secret lives | Credentials can sit on the application object or directly on the service principal | Check application.passwordCredentials and servicePrincipal.passwordCredentials; this guide covers the application object |
| You know every consumer | One secret is often pasted into several systems | Service principal sign-ins grouped by IP address and credential key ID (step 2), plus the owner |
| Least-privilege permission | Rotation should not need tenant-wide write | Delegated: Application Developer for owned apps, or Cloud Application Administrator; application: Application.ReadWrite.OwnedBy with the automation as an app owner |
| Sign-in log access | Proof of quiet comes from the logs | At least Reports Reader in the admin centre; AuditLog.Read.All for Graph queries |
| App management policy | A tenant restriction may block new secrets | Check whether passwordAddition or passwordLifetime is enforced (Entra ID > Enterprise apps > Application policies) |
Step-by-step
Steps 1 and 2 are read-only. Step 3 adds a credential and is reversible by removing it. Step 6 is the destructive step.
- Record the current secrets. Note each secret's
keyId,displayName,hint(the first characters of the value) andendDateTime.
The hint lets an owner match the secret in a consumer's configuration to aConnect-MgGraph -Scopes 'Application.Read.All' (Get-MgApplication -ApplicationId '<object-id>').PasswordCredentials | Select-Object DisplayName, KeyId, Hint, StartDateTime, EndDateTimekeyIdwithout anyone handling the full value. - Find every consumer of the old secret. Query service principal sign-ins and group by credential key ID and IP address. Service principal sign-ins are returned only when you filter for them explicitly:
Narrow it withGET https://graph.microsoft.com/beta/auditLogs/signIns?$filter=signInEventTypes/any(t: t eq 'servicePrincipal')servicePrincipalIdfor your app. In each record,clientCredentialTypeshowsclientSecret,certificate,federatedIdentityCredentialand so on, andservicePrincipalCredentialKeyIdis "the unique identifier of the key credential used by the service principal to authenticate". Each distinctipAddressusing the oldkeyIdis a consumer to move. In the admin centre the same records are under Entra ID > Monitoring & health > Sign-in logs > Service principal sign-ins, where rows are grouped by service principal, status, IP address and resource. - Add the new secret. Give it a description that names the consumer and date, and an end date that matches your rotation cycle.
The raw call isConnect-MgGraph -Scopes 'Application.ReadWrite.All' $cred = @{ displayName = 'payroll-sync 2026-11'; endDateTime = (Get-Date).AddMonths(6) } $secret = Add-MgApplicationPassword -ApplicationId '<object-id>' -PasswordCredential $credPOST /applications/{id}/addPasswordwith an optionalpasswordCredentialobject holdingdisplayName,startDateTimeandendDateTime. Without an end date the secret lasts two years from its start. The response returnskeyId,hintandsecretText, a generated value of 16 to 64 characters that "can't be retrieved later". In the portal the path is App registrations > app > Certificates & secrets > Client secrets > New client secret, and the value is displayed only once. - Write the value to the consumer's store and reload. Pipe
$secret.SecretTextdirectly into Key Vault (Set-AzKeyVaultSecretoraz keyvault secret set) or the CI secret variable, never into a ticket, chat or terminal log. Consumers that read the secret only at start-up must be restarted. If a supplier holds the secret in their platform, agree a window when both secrets will be valid. - Prove the new key ID is in use and the old one is quiet. Re-run the step 2 query. The new
keyIdshould appear from every expected IP address; the oldkeyIdshould stop appearing. Microsoft's recommendation workflow ends the same way: validate in the sign-in logs that the key ID of the new credential matches the one you added, then remove the old one. Wait long enough to cover weekly and month-end jobs. - Remove the old secret.
The Graph call isRemove-MgApplicationPassword -ApplicationId '<object-id>' -KeyId '<old-key-id>'POST /applications/{id}/removePasswordwith body{"keyId": "<old-key-id>"}, which returns204 No Content. Removing is better than waiting for expiry, because an expired secret left on the app hides the real credential count and invites someone to "extend" it.
Choosing a rotation approach
| Approach | Best for | Trade-off |
|---|---|---|
| Manual overlap (this guide) | A handful of apps with known owners | Human effort; the quiet-period check is easy to skip |
| Pipeline-driven rotation into Key Vault | Many apps whose consumers read from Key Vault | The automation identity needs Application.ReadWrite.OwnedBy and ownership of each app; consumers must reload |
| Event-driven rotation | Secrets stored in Key Vault with an expiry date | Microsoft's rotation tutorials use the Key Vault SecretNearExpiry event, raised 30 days before expiry, to trigger a Function |
| Switch to a certificate | Workloads that can hold a private key | Still needs rotation, but the private key never travels to Entra |
| Managed identity or federated credential | Azure-hosted workloads, GitHub Actions, Kubernetes, other clouds | One-off migration; no secret left to rotate. See How to replace Azure app secrets with federated credentials |
Small tenants with a few dozen secrets should rotate manually once, then spend the effort on removing secrets. Large tenants should assume manual rotation will not keep up: set lifetimes through policy, rotate through a pipeline, and track the number of secrets as the headline figure that must fall.
Automating the rotation safely
Manual rotation does not scale past a few dozen apps. A rotation pipeline repeats the same six steps, and its own identity becomes one of the most sensitive in the tenant, so build it narrowly.
- Scope the automation identity: grant the application permission
Application.ReadWrite.OwnedBy, which Microsoft lists as the least-privileged application permission foraddPasswordandremovePassword, and make the automation an owner of only the apps it rotates. AvoidApplication.ReadWrite.AllandDirectory.ReadWrite.All. - Give the pipeline itself no secret: run it under a managed identity or a federated credential, otherwise you have created a secret to rotate the secrets.
- Write, then promote: add the new password, store
secretTextas a new Key Vault secret version, tag it with the EntrakeyId, and only then signal consumers to reload. Microsoft's dual-credential Key Vault tutorial uses aCredentialIdtag in the same way to record which credential the current version holds. - Gate removal on evidence: the pipeline removes the old
keyIdonly after a sign-in query shows no use of it for the agreed quiet period, and opens a ticket instead of removing when it is still in use. - Log every change: each run records application, old and new key IDs and timestamps, which gives auditors the rotation history without exposing values.
Consumers need one change for this to work: they must read the secret from Key Vault at start-up or on a refresh interval, not from a configuration file baked into a release. Where a consumer cannot do that, it stays on manual rotation and goes to the top of the list for migration to a managed identity.
Verify it worked
- Credential list: the app shows one current secret with the new
keyIdand the expected end date. - Sign-ins: successful service principal sign-ins carry the new
servicePrincipalCredentialKeyId; none carry the old one. - No failures: no failed sign-ins for the service principal after removal. AADSTS7000215 means an invalid secret was presented, AADSTS7000222 means it has expired; the Entra Service Principal Sign-In Errors Guide covers both.
- Audit trail: the Entra audit log records the credential change on the application, and the change ticket references both key IDs.
Rollback and common errors
| Symptom | Likely cause | Fix |
|---|---|---|
| A consumer fails after removal | It still held the old secret | No undo for removePassword: add another new secret, give it to that consumer, investigate why step 2 missed it |
| New secret value lost | Not captured at creation | Remove that keyId and add another; the value cannot be retrieved |
addPassword refused by policy | passwordAddition or passwordLifetime restriction applies | Use a shorter end date, or take the hint and move to a certificate or federated credential |
| 403 from Graph in automation | Automation is not an owner of the app when using Application.ReadWrite.OwnedBy | Add the automation's service principal as an owner of that app, not a broader permission |
| Old key ID still signing in days later | Unknown consumer or cached configuration | Trace by IP address; do not remove until found |
| Rotated the wrong object | Secret sits on the service principal, not the application | Check servicePrincipal.passwordCredentials and rotate there |
Detection and measurement
- Credential additions: alert on new password credentials added to applications outside a change window. Adding credentials to an existing app is a persistence technique, MITRE ATT&CK T1098.001 Additional Cloud Credentials. The Entra ID Sign-In and Audit Log Detection Guide has the queries.
- Retired key in use: any sign-in with a removed or retired
servicePrincipalCredentialKeyIdis an error to fix or a sign of misuse. - Weak credential types: Microsoft describes
clientCredentialTypeas a way to "track and eliminate less secure credential types"; trend the share ofclientSecretsign-ins.
Metrics:
- Number of client secrets in the tenant, trending down.
- Percentage of secrets with an end date within policy (for example 6 or 12 months).
- Apps with more than one active secret outside a rotation window.
- Rotations that caused a failed-sign-in incident, per quarter.
- Median days from new secret creation to old secret removal.
Common failure patterns
- Extending instead of rotating: creating a long-lived replacement but never removing the old one leaves two valid secrets for years.
- One secret, many consumers: a single secret pasted into several tools makes every rotation a cross-team project. Use one app registration per integration.
- Removing on expiry day: waiting for the expiry alert leaves no time for the quiet period; start 30 days out.
- Over-privileged rotation automation: granting
Application.ReadWrite.Allto a script lets a compromise of that script add secrets to every app in the tenant. - Ignoring vendor-held secrets: secrets given to SaaS suppliers are rarely in anyone's rotation plan; record them in the Azure Entra Client Secrets Security Guide inventory approach.
Hardening afterwards
- Restrict new secrets: use app management policy restrictions
passwordAddition,passwordLifetimeandcustomPasswordAddition(blocks user-supplied values) for new apps first, then extend. - Move to stronger credentials: certificates, managed identities or federated identity credentials, in that order of preference for workloads that can use them.
- Clean up: rotation is the right moment to ask whether the app is still needed. See How to find and remove stale service principals in Entra ID.
Framework mapping
| Framework | Reference | Relevance |
|---|---|---|
| NIST SP 800-53 Rev 5 | IA-5 Authenticator Management | Lifetime, change and protection of client secrets |
| NIST SP 800-53 Rev 5 | AC-2 Account Management | Owners and purpose for each app registration |
| NIST SP 800-53 Rev 5 | AU-6 Audit Record Review, Analysis, and Reporting | Reviewing service principal sign-ins and credential changes |
| NIST CSF 2.0 | PR.AA-01 | Credentials for services are managed by the organisation |
| MITRE ATT&CK | T1098.001 Additional Cloud Credentials; T1078.004 Cloud Accounts | Detecting added credentials and limiting the life of stolen ones |
Practitioner checklist
- Confirm the trigger is routine; a confirmed leak means remove now.
- Record every secret's
keyId, hint and end date. - Map consumers from service principal sign-ins by credential key ID and IP address.
- Add the new secret with a descriptive name and policy-length end date.
- Write the value straight to Key Vault or the consumer's store and reload consumers.
- Confirm the new key ID in sign-ins and silence from the old one over a full cycle.
- Remove the old secret with
removePassword. - Record a plan to replace the secret with a certificate, managed identity or federated credential.
Standards and references
- Microsoft Graph: application addPassword
- Microsoft Graph: application removePassword
- Microsoft Graph (beta): signIn resource type
- Microsoft Learn: Renew expiring application credentials recommendation
- Microsoft Learn: Configure app management policies
- Microsoft Learn: Add-MgApplicationPassword
- Microsoft Learn: Service principal sign-ins
- Microsoft Learn: Rotation for resources with two sets of credentials
Related NHI Mgmt Group resources: Azure Entra Client Secrets Security Guide · How to find expiring app secrets and certificates in Entra ID · How to replace Azure app secrets with federated credentials · How to rotate an AWS IAM access key without downtime