Open source

Entra Credential Monitor

Every Entra ID tenant accumulates app registrations, and every app registration holds secrets and certificates that expire. Nobody notices until the integration they power stops working. This monitor notices a month earlier — read-only, monthly, and with nothing to operate in between.

The problem

An expired client secret is the outage nobody planned for — because nothing was watching it.

Application credentials are the plumbing of an Entra ID tenant: integrations, daemons, and pipelines all authenticate with secrets and certificates that have expiry dates set months or years earlier, by someone who may no longer be around. The portal will not call you when one lapses; the integration just stops. We built the monitor for real client environments — and maintain it in the open, because this problem is nobody’s competitive advantage.

What we built

A monthly, read-only sweep that ends in one email worth reading.

Once a month, the monitor signs into each client tenant with three read-only Microsoft Graph permissions and sweeps every app registration and service principal for client secrets and certificates. Each credential is classified — expiring within thirty days, recently expired, or long expired — and the result is a single email that leads with what to act on. Ancient history is capped to a short reference table, so the report stays readable instead of becoming the thing nobody opens.

The report

Real renderer, invented data: this is the email a tech receives when credentials approach expiry.

The Entra ID Security Report email: one credential expired and three approaching expiry, a fix-before-expiry table with days left and owners, a restore-or-remove section flagging an ownerless credential, and a priority brief saying what to do first. Illustrative Contoso data.

Rendered by the product’s real email renderer with invented Contoso data — client reports carry their own tenants’ credentials.

How it works

Zero standing infrastructure: for a few minutes a month it exists, then it doesn’t.

Monthly wake-up the 1st of the month, a dead-man timer watching An ephemeral runner, per client tenant exists for minutes, then is gone Sign in read-only: three Graph permissions Scan every app & principal: secrets & certificates Classify expiring · just expired · long expired One email leads with what to act on; ancient history capped in between: nothing is running — no server, no standing secrets beyond one vault token
Zero standing infrastructure: the CI scheduler is the cron, each tenant gets its own short-lived runner (one broken tenant cannot hide another’s report), and the output is a single email that leads with what to do.

There is no server to patch and no dashboard to forget: the CI scheduler is the cron, each tenant runs in its own short-lived job (so one broken tenant cannot hide another’s report), and secrets are resolved at runtime from a vault — the only stored credential is a single service-account token. The engineering theme throughout is fail loud, never fake a green: malformed Graph records are counted and reported rather than silently dropped, an unparseable expiry date is treated as critical rather than filtered out, and a bad configuration aborts the run instead of quietly narrowing the scan.

Who watches the watchman

The monitor authenticates with a credential that also expires. It treats its own expiry as the most important one.

The monitor signs in with a credential that also expires warned 30 days out Everyone else’s credentials apps & service principals, all tenants warned 60 days out Its own credentials found by its own app id, every run cannot find itself, or no credentials? CRITICAL
The watchman watches itself, with twice the warning horizon — the monitor’s own credential expiring is how the whole system would go dark, so it warns about itself a month before it warns about anyone else. The dead-man timer catches the case where it never runs at all.

Decisions worth noting

  • Read-only by construction. Three Graph permissions, none of them write. The blast radius of the monitor itself is zero — the least-privilege posture we ask of every automation.
  • Fail loud, never fake a green. The dangerous failure mode of any monitor is a false all-clear. Every path that could silently shrink the scan — schema mismatches, unparseable dates, paging failures, bad config — either surfaces in the report or aborts the run visibly.
  • A failed email cannot email about itself. The failure path is explicitly barred from using the channel that just failed — that alert goes to the job summary and the dead-man timer instead.
  • The report is engineered, not templated. The HTML email stays under Gmail’s clipping threshold — enforced by a size-budget test — and renders in Outlook, which strips most styling. Deliverability is a correctness property.
  • Classified failures with operator guidance. Nine failure kinds, each carrying a recommended action — the person on call should never have to reverse engineer what went wrong.

Built with

  • TypeScript
  • Microsoft Graph

What's quietly expiring in your tenant?

Cloud, network, and security engagements with a fixed scope and a fixed price — delivered as code you own.