It is the classic 3am page: an integration suddenly starts failing with
AADSTS7000222, "the provided client secret keys are expired." Nothing was
deployed, nothing changed, except a client secret on an app registration quietly reached its
end date. Entra ID knows the exact expiry date of every client secret and certificate in the
tenant, and it tells no one. The ask for native owner alerts has sat on the Azure feedback
forum for over six years with 223+ votes, and it is still unaddressed.
Why Entra cannot alert you out of the box
- There is no built-in expiry notification. The portal shows each secret's expiry date on the app registration blade, but nothing watches those dates for you. No email, no alert rule, no Action Group hook.
- The data is scattered across every app registration. Each registration
carries its own
passwordCredentials(client secrets) andkeyCredentials(certificates), so "what expires in the next 30 days?" means walking the whole tenant, not checking one dashboard. - You find out when authentication fails. The first signal most teams get is the outage itself: token requests start returning errors, and the scramble to find which app, which secret, and who owns it happens under incident pressure.
The DIY approach: a scheduled Microsoft Graph scan
The fix is a small scheduled job that reads the expiry dates while there is still time to rotate:
- Run a daily timer job (an Azure Function works well) under a managed identity, so there is no credential for the watcher itself to expire.
- Grant that identity the Application.Read.All Microsoft Graph application role. That is enough to list registrations and read credential metadata; it never exposes secret values.
- Call
GET /v1.0/applicationsand, for every app, read theendDateTimeon each entry inpasswordCredentialsandkeyCredentials. Remember to follow paging, or a large tenant silently truncates. - Compute days to expiry and compare against a ladder of thresholds, for example 30, 14, 7, and 1 days, so a missed first warning still gets louder ones.
- Post matches to a Teams webhook with the app name, credential type, and days remaining, so the alert lands where the owning team already works.
The details that bite in practice: certificates expire too (do not scan only
passwordCredentials), one registration can carry several credentials in different
states, and a single-threshold script that fires once and goes quiet is easy to miss. The
escalation ladder is what turns "we technically sent an email" into "someone actually rotated
the secret."
A ready-made option: Secret Sentinel
Secret Sentinel is that pattern packaged. A daily timer Function scans every app registration
in the tenant via Microsoft Graph, computes days to expiry for every client secret and
certificate, and alerts your Teams channel at 30, 14, 7, and 1 days before anything expires
(thresholds you choose at deployment). It authenticates with a system-assigned managed
identity holding only Application.Read.All, reads expiry dates and never secret
values, and runs entirely in your own subscription with no vendor backend.
Key facts
- Native expiry alerting in Entra ID: none; the portal shows dates but notifies no one.
- Where the data lives:
passwordCredentials&keyCredentialson each application object in Microsoft Graph. - Least privilege:
Application.Read.Allis sufficient; secret values are never readable this way, only metadata. - Durable fix: a scheduled scan with escalating thresholds (30/14/7/1 days) posting to the owning team's channel.
Related reading: set an Entra ID account to expire automatically.
Written by the team at Katabarwa Labs. We build small, single-purpose Azure tools that run entirely inside your own tenant. Questions: abaho@llmgraph.ai.