Entra ID (formerly Azure AD) app registrations are the backbone of modern cloud services, integrations, and CI/CD pipelines. Applications often use a client secret with a lifetime of 6–24 months.

The problem? When a secret finally expires, it often happens without anyone remembering it. The developer who created it may have changed jobs, and the documentation may be missing.

The best solution: eliminate secrets altogether

Before building monitoring for expiring secrets, consider whether you can remove the secrets entirely:

  • Managed Identity: Azure services such as Azure App Service, Azure Functions, and virtual machines do not need passwords to communicate with one another. Use a user-assigned or system-assigned managed identity whenever possible.
  • Workload Identity Federation (OIDC): GitHub Actions and GitLab do not need to store long-lived client secrets. Instead, use OIDC-based federated authentication so GitHub receives a short-lived token directly from Entra ID.

How to monitor existing secrets

Not every secret can be removed, especially when it belongs to a third-party integration or an external SaaS service. In these cases, monitoring is essential.

The following simple PowerShell script uses the Microsoft Graph PowerShell module to list all secrets and certificates that expire within 30 days:

# Connect to Microsoft Graph with the required permissions
Connect-MgGraph -Scopes "Application.Read.All"

$warningThresholdDays = 30
$now = Get-Date

$apps = Get-MgApplication -All
$expiringSecrets = @()

foreach ($app in $apps) {
    # Check passwords (client secrets)
    foreach ($password in $app.PasswordCredentials) {
        if ($password.EndDateTime -and $password.EndDateTime -lt $now.AddDays($warningThresholdDays)) {
            $expiringSecrets += [PSCustomObject]@{
                AppName       = $app.DisplayName
                AppId         = $app.AppId
                Type          = "PasswordSecret"
                Hint          = $password.Hint
                Expires       = $password.EndDateTime
                DaysRemaining = [math]::Round(($password.EndDateTime - $now).TotalDays)
            }
        }
    }
}

# Print alerts
$expiringSecrets | Sort-Object DaysRemaining | Format-Table

Automatic alerts in Teams or Slack

You can easily run the script once a week as a runbook in an Azure Automation account or as a scheduled Azure Function. If secrets expiring within the next 30 days are found, the script can notify the team’s Teams or Slack channel or automatically create a support ticket.

🛡️ Want to clean up and secure your Entra ID permissions?

I can help identify outdated application credentials, remove unnecessary role assignments, and migrate applications to a secure Managed Identity and OIDC architecture.

Explore cloud governance services →