What Is App Registration Credential Hygiene in Entra
Entra app registration credential rotation secrets are the client secrets, certificates, and federated credentials your applications use to authenticate, and they are one of the most overlooked corners of the identity attack surface in a tenant. Every app registration that authenticates as itself, whether a daemon, a CI/CD pipeline, or an API integration, needs a credential to prove it is who it says it is. That credential is a passwordCredential (a client secret), a keyCredential (an uploaded certificate public key), or a federated credential (a trust relationship with an external identity provider, no secret material at all). Forgetting to rotate any of these is how a routine credential quietly becomes a standing backdoor with no MFA prompt and often no owner watching it.
This matters because an app registration's credential grants whatever that application's permissions grant: Microsoft Graph API scopes, delegated or application permissions, sometimes directory-wide read/write access. Microsoft's own guidance is explicit: client secrets are less secure than certificate or federated credentials and should not be used in production; with workload identity federation, you eliminate the maintenance burden of manually managing credentials and the risk of leaking secrets or having certificates expire. A tenant that never inventories app credentials has no way to tell a routine secret from one that has quietly outlived every admin who knew what it was for.
This is a different angle from over-permissioned app registrations (covered in Azure App Registrations: Over-Privileged Tenant Apps) — that piece is about what an app can do; this one is about how long its keys to the door stay valid, and whether anyone is watching the lock. A leaked long-lived secret gets used the same way a phished OAuth token does in OAuth Consent Phishing: silently, with the app's own permissions, until someone notices the activity doesn't match the app's normal behavior.
How It Works: Secrets, Certificates, and Why Rotation Gets Skipped
Every application and servicePrincipal object in Microsoft Graph exposes two credential collections:
passwordCredentials— client secrets, each with akeyId,startDateTime, andendDateTime. Per the passwordCredential resource reference,endDateTimeis the ISO 8601 UTC timestamp after which the secret stops working.keyCredentials— uploaded certificate public keys used for certificate-based authentication (CBA), each with its own expiry.
Portal-created client secrets are capped at a 24-month maximum lifetime, and Microsoft explicitly recommends setting an expiration under 12 months rather than defaulting to the maximum. In practice, teams often do the opposite: they pick the longest expiry offered so nothing breaks unexpectedly, then leave the app alone. Two years later the person who set it up has left, the secret is still valid, and nobody remembers which pipeline or script depends on it.
A related but distinct problem is credential sprawl: an application accumulating multiple active secrets over time because rotation was done by adding a new secret rather than replacing the old one. Each additional live secret is another way in that has to be tracked, revoked, and audited — and old secrets from a rotation that "worked" are routinely never cleaned up. It is common to find app registrations several years old carrying three or four active secrets, each created by a different admin during a different incident, none of them ever revoked.
Certificate-based authentication is generally the safer of the two credential types — a certificate's private key never has to be transmitted or pasted into a config file the way a secret value does. But an active CBA certificate is still a live credential with an expiry and a blast radius if the private key is compromised, and Microsoft recommends certificates be issued from a trusted CA with a policy enforcing trusted issuers rather than self-signed certs with indefinite trust.
⚠️ Warning: A client secret and an uploaded certificate look identical in terms of access — both authenticate the app with whatever permissions it holds. The difference is operational: a certificate's private key typically never leaves the system that generated it, while secret values get copied into pipelines, .env files, and key vaults by hand.
Detecting Entra App Registration Credential Rotation Secrets That Are Stale or Sprawling
Start with an inventory, not a spot check — you cannot rotate what you have not counted.
Inventory every credential via Microsoft Graph
Query every application's credentials directly:
GET https://graph.microsoft.com/v1.0/applications
?$select=id,displayName,passwordCredentials,keyCredentials
The response includes endDateTime for every secret and certificate, letting you flag anything already expired or expiring soon.
Script it across the tenant with PowerShell
The Microsoft Graph PowerShell SDK makes this easier to run tenant-wide rather than app by app:
# Requires: Connect-MgGraph -Scopes "Application.Read.All"
Get-MgApplication -All -Property Id, DisplayName, PasswordCredentials, KeyCredentials |
ForEach-Object {
$app = $_
$app.PasswordCredentials | ForEach-Object {
[PSCustomObject]@{
App = $app.DisplayName
Type = "Secret"
KeyId = $_.KeyId
Expires = $_.EndDateTime
DaysLeft = ($_.EndDateTime - (Get-Date)).Days
}
}
$app.KeyCredentials | ForEach-Object {
[PSCustomObject]@{
App = $app.DisplayName
Type = "Certificate"
KeyId = $_.KeyId
Expires = $_.EndDateTime
DaysLeft = ($_.EndDateTime - (Get-Date)).Days
}
}
} | Sort-Object DaysLeft
Read the signals that matter
From that inventory, map findings to concrete risk:
| Signal | What it means | What to look for |
|---|---|---|
| No credential change in the app's lifetime | Rotation isn't happening at all | passwordCredentials/keyCredentials startDateTime unchanged since app creation, long past any reasonable rotation cadence |
| Secret expiry set far in the future | Long-lived secret by design | endDateTime set close to the 24-month portal maximum instead of the Microsoft-recommended sub-12-month window |
| More than one active secret | Credential sprawl from additive rotation | passwordCredentials array with 2+ entries where endDateTime is still in the future |
| Active certificate-based auth | CBA in use — verify it's still expected and CA-trusted | Non-empty keyCredentials with usage: Verify and a live endDateTime |
Confirm live usage in sign-in logs
Verify how credentials are actually being used, not just what exists, via service principal sign-in logs. Each sign-in event carries a ClientCredentialType field: a value of client secret indicates password-based authentication, while certificate-based auth shows up as client assertion, alongside a ClientCredentialKeyID you can match back to the specific keyId in the app's credential list. That mapping tells you which credential is actually live in production versus which ones are dead weight nobody removed — a distinction the raw credential inventory alone cannot give you. If a credential shows up flagged in a risk detection rather than a routine sign-in, treat it the way Azure Identity Protection: Blocking Leaked Credentials recommends handling any other leaked-credential signal.
Track credential changes in the audit log
For historical change tracking, filter the Entra audit log by Category = ApplicationManagement: application and service principal credential additions and removals are logged as target-resource modified-property changes you can review per app — see the Microsoft Entra audit log activity reference. Export these to a SIEM or Log Analytics workspace if you need retention longer than the admin center's default window, per the audit logs overview.
Remediation: Rotating, Restricting, and Moving Off Secrets
💡 Tip: Where the workload supports it — GitHub Actions, Kubernetes workloads, Azure DevOps, compute outside Azure — replace the secret entirely with a federated credential (workload identity federation). There is no value to leak and no expiry to track because there is no secret material at all.
Inventory first, rotate second
Run the Graph query above across every application before touching anything — you need to know which secrets are actually referenced by a running workload before revoking them. Rotating or deleting a secret still in use breaks the workload that depends on it, so this step is not optional.
Replace, don't add
When rotating, create the new secret or certificate, update the consuming workload, verify it authenticates, then delete the old credential. Adding a new one and leaving the old one "just in case" is how multi-secret sprawl happens in the first place.
Move to certificates or federated credentials
Microsoft recommends certificates over client secrets before an app reaches production, and federated credentials where the workload platform supports it — eliminating the rotation problem outright instead of managing it better.
Enforce the standard tenant-wide
Rather than relying on every app owner to self-police, enforce credential standards with an Application Management Policy. Policies are configured via Microsoft Graph or Graph PowerShell (no portal UI) and can cap certificate lifetime and block new password credentials outright:
# Requires: Connect-MgGraph -Scopes "Policy.ReadWrite.ApplicationConfiguration"
$policy = @{
displayName = "Enforce credential standards"
isEnabled = $true
applications = @{
keyCredentials = @(
@{
restrictionType = "asymmetricKeyLifetime"
maxLifetime = "P180D"
state = "enforced"
}
)
passwordCredentials = @(
@{
restrictionType = "passwordAddition"
state = "enforced"
}
)
}
}
New-MgPolicyAppManagementPolicy -BodyParameter $policy
See the tutorial on enforcing secret and certificate standards and configuring app management policy restrictions for the full restriction types available, including scoping a policy to specific apps versus tenant-wide.
Assign an owner and review on a cadence
A credential nobody owns is a credential nobody rotates or revokes when it should be. Pair ownership with a recurring review of the inventory query above — monthly at minimum for apps holding privileged Graph permissions.
Verify certificate trust, not just expiry
For CBA specifically, confirm active certificates come from a trusted CA per your security best practices for app registration properties, not a self-signed cert nobody remembers issuing.
Related reading: Entra SAML Signing Certificate Expired covers what happens when a different certificate type — SAML signing — is left to expire unmonitored, and How to Audit Microsoft Entra ID Security walks through app permissions review as part of a broader tenant audit.
How EtcSec Detects This
EtcSec's Entra audit checks application and service principal credentials directly against Microsoft Graph on every scan. APP_NO_CREDENTIAL_ROTATION flags apps whose credentials have gone stale with no replacement activity; APP_SECRET_LONG_EXPIRY and APP_SECRET_EXPIRED catch secrets set for excessive lifetimes or already past endDateTime; APP_MULTIPLE_SECRETS surfaces credential sprawl from additive rotation; SP_STALE_CREDENTIAL extends the same check to service principals; and CBA_CERTIFICATES_ACTIVE inventories every application currently relying on certificate-based authentication so you can verify trust and expiry deliberately instead of finding out when it breaks.
ℹ️ Note: EtcSec automatically checks for these credential-hygiene gaps during every Azure/Entra audit. Run a free audit to see which of your app registrations are carrying stale or sprawling credentials today, alongside every other Entra and Active Directory misconfiguration in the catalogue.
Explore the identity security pages that support this topic
