BUYER'S GUIDE | IDENTITY SECURITY
Buyer's GuideUpdated 11 min read

Azure App Registration Secret Expiry at Scale: How to Audit and Rotate Client Secrets Across 100 or More Applications Before They Break

24 months
the maximum client secret lifetime allowed in Azure app registrations. Secrets created with 24-month expiry in 2024 are expiring now across enterprise tenants, creating a wave of authentication failures in 2026
0
the number of automatic notifications Microsoft sends when an app registration client secret expires. Without proactive monitoring, expiry is discovered only when the application it authenticates starts failing
100+
the typical number of app registrations in an enterprise Microsoft 365 or Azure tenant that has been in production for three or more years, making manual expiry tracking unworkable without automation
30 days
the recommended alert window before secret expiry: enough lead time to identify the application owner, test the new secret in a non-production environment, and coordinate the production rotation without a rushed deployment

SponsoredRetool

Retool's new app builder is where AI-generated code ships safely

Building apps with AI is easy. Getting them to production safely is another story.

Start building for free today

App registration client secrets expire without warning. The application that uses the secret throws an AADSTS7000222 error or a generic 401 Unauthorized response, and the first person to know is whoever is on-call when the monitoring alert fires at 2am. In most organizations, no one knows how many app registrations exist, which secrets are expiring, or which application each secret belongs to.

The problem scales with tenure. An Azure tenant in production for three years with active development teams will have 100 to 300 app registrations. Many of those registrations have multiple secrets, some created by developers who have since left. The 24-month maximum secret lifetime means a wave of expirations is always approaching.

This guide covers the Graph API queries that surface every expiring secret across all app registrations, the rotation procedure that avoids the most common outage pattern, and the automation pattern for a weekly expiry alert.

Enumerate all app registrations and their secret expiry dates

The Graph API endpoint for app registrations returns passwordCredentials (client secrets) and keyCredentials (certificates) as arrays with their expiration dates.

Graph API request: GET https://graph.microsoft.com/v1.0/applications?$select=displayName,id,appId,passwordCredentials,keyCredentials&$top=999

PowerShell with Microsoft Graph module: Connect-MgGraph -Scopes 'Application.Read.All' then Get-MgApplication -All -Property DisplayName,Id,AppId,PasswordCredentials,KeyCredentials

For each application, the passwordCredentials array contains objects with endDateTime (expiry date), startDateTime (creation date), keyId (unique identifier), and hint (last 3 characters of the secret, useful for identifying which secret is in use).

Filter for secrets expiring within 90 days: $threshold = (Get-Date).AddDays(90) $apps = Get-MgApplication -All -Property DisplayName,Id,AppId,PasswordCredentials foreach ($app in $apps) { $expiring = $app.PasswordCredentials | Where-Object { $.EndDateTime -lt $threshold -and $.EndDateTime -gt (Get-Date) } if ($expiring) { [PSCustomObject]@{ App = $app.DisplayName; AppId = $app.AppId; ExpiresOn = $expiring.EndDateTime } } } | Sort-Object ExpiresOn | Export-Csv expiring_secrets.csv

Run separately for keyCredentials to catch expiring certificates.

Identify the application owner for each expiring secret

The app registration record does not directly record which production system or codebase uses the secret. Two lookups help narrow this down.

First, check the app registration owner: GET /v1.0/applications/{id}/owners returns the Entra ID users or service principals listed as owners. These are the first contact for rotation coordination.

Second, correlate the appId with sign-in logs to find which application is actively using the secret: GET /v1.0/auditLogs/signIns?$filter=appId eq '{appId}'&$top=10 shows recent sign-in events. The resource field in each sign-in event shows which service the app is authenticating to. The clientAppUsed and deviceDetail fields sometimes reveal which deployment is using the credential.

For secrets with no recent sign-in activity (no sign-ins in 90+ days), the secret may be used by a batch process that runs infrequently. Check the application display name against your CMDB or deployment documentation before concluding the secret is unused.

Document the findings: app display name, app ID, secret expiry date, hint characters, owner, last sign-in date, and owning team or system. This becomes the rotation work queue.

Free daily briefing

Briefings like this, every morning before 9am.

Threat intel, active CVEs, and campaign alerts, distilled for practitioners. 50,000+ subscribers. No noise.

Safe rotation procedure: create before delete

The most common rotation mistake is deleting the existing secret before updating the application configuration. This creates an outage window between deletion and the application deploying its new secret. The correct procedure is create-update-verify-delete.

Step 1: Create a new secret on the existing app registration. In the Azure portal: App registrations > [app] > Certificates and secrets > New client secret. Via PowerShell: Add-MgApplicationPassword -ApplicationId {id} -PasswordCredential @{DisplayName='Rotation-2026'; EndDateTime=(Get-Date).AddMonths(12)}

Step 2: Update the application configuration with the new secret value. The update mechanism varies by deployment: environment variable in App Service, Key Vault secret reference, Kubernetes secret, or application configuration file. Do not delete the old secret yet.

Step 3: Deploy and verify. Confirm the application authenticates successfully with the new secret by reviewing sign-in logs for the appId. Look for successful sign-in events that post-date your configuration update. Wait at least 24 hours in production before proceeding.

Step 4: Delete the old secret using the keyId from the original enumeration. Via Graph API: DELETE /v1.0/applications/{id}/removePassword with body {keyId: '{keyId}'}.

The wait period between steps 3 and 4 catches the case where the new secret was deployed to some but not all instances (common in autoscaling environments where old instances are still running with the cached old secret).

Automate weekly expiry alerts

A weekly report of secrets expiring within 30, 60, and 90 days prevents the reactive scramble. The implementation pattern that requires the fewest moving parts is a PowerShell script running on a schedule in Azure Automation or GitHub Actions.

Azure Automation approach: create an Automation Account with a System-Assigned Managed Identity, grant the managed identity Application.Read.All permission in Entra ID, create a PowerShell runbook that runs the expiry enumeration script weekly, and outputs results to an email via SendGrid or a Teams webhook.

GitHub Actions approach: create a workflow that runs on a cron schedule (weekly), uses a service principal with Application.Read.All to run the Graph API enumeration, and posts to a Slack or Teams channel using an incoming webhook. This approach works well for teams that manage infrastructure as code and prefer GitHub as the execution environment.

For both approaches, segment the output into three urgency tiers: expiring in less than 30 days (immediate action required, tag the owning team), 30 to 60 days (schedule rotation in current sprint), 60 to 90 days (add to backlog). Color-code the output and include the direct Azure portal link to the app registration for each entry.

The bottom line

App registration secret expiry is an operational problem that looks like a security incident when it hits production. The Graph API exposes every secret and its expiry date in a single query. The rotation procedure is straightforward if you create the new secret before deleting the old one. The prevention is a weekly automated report with a 90-day warning window that gives teams enough lead time to rotate without a crisis. None of this requires third-party tooling; the Microsoft Graph PowerShell module and an Azure Automation Account are sufficient. For teams looking to eliminate long-lived secrets from app registrations entirely, the Azure Key Vault access policy and RBAC migration guide covers transitioning to managed identity-based secret retrieval.

Frequently asked questions

How do I find all expiring client secrets across all Azure app registrations?

Use the Microsoft Graph API: Get-MgApplication -All -Property DisplayName,Id,AppId,PasswordCredentials in PowerShell with the Microsoft Graph module. The PasswordCredentials property on each application contains an EndDateTime field for each secret. Filter for EndDateTime less than 90 days from today to get your rotation work queue. This requires Application.Read.All permission granted to your account or service principal.

What happens when an Azure app registration client secret expires?

The application receives an AADSTS7000222 error (ClientSecretExpired) or a generic 401 Unauthorized response when it attempts to acquire an access token using the expired secret. The failure is immediate and affects all instances of the application simultaneously. There is no grace period after expiry. Applications that cache tokens will continue working until the cached token expires (typically 1 hour), at which point they will also fail when attempting to refresh.

Can I extend the expiry date on an existing Azure app registration secret?

No. Azure does not support extending the expiry date of an existing client secret. The only option is to create a new secret and delete the old one after updating the application. This is by design: extending expiry on a secret that may have been compromised would defeat the purpose of secret rotation. The maximum lifetime for a new client secret is 24 months.

How can I tell which application is using a specific app registration secret?

The hint field on each PasswordCredential shows the last three characters of the secret value, which lets you match a secret in the portal to a value stored in an application's configuration. For runtime identification, query sign-in logs using the appId: GET /v1.0/auditLogs/signIns?$filter=appId eq '{appId}' to see which service the application has been authenticating to and from which IP addresses. Cross-reference those IPs with your infrastructure inventory to identify the hosting environment.

What is workload identity federation and how does it replace app registration secrets?

Workload identity federation allows Azure workloads (GitHub Actions, Kubernetes pods, other cloud services) to authenticate to Entra ID using their platform's identity token instead of a client secret or certificate. The workload's identity provider (GitHub, AWS, GCP, or a Kubernetes cluster) issues a short-lived OIDC token; Entra ID validates that token against a configured trust relationship and issues an access token. No secrets are stored anywhere — there is nothing to rotate, expire, or leak. For GitHub Actions: configure a federated credential on the app registration pointing to github.com/org/repo as the issuer, then use the OIDC login action in your workflow. This eliminates the secret rotation burden and removes secrets from CI/CD configuration entirely.

Should I use certificates or client secrets for app registrations that cannot use workload identity federation?

Certificates are strongly preferred over client secrets for any app registration that requires a credential. Certificates have a public/private key structure: the private key stays on the server or in a key vault and is never transmitted to Entra ID during authentication (unlike a secret, which is the credential itself). A compromised certificate private key is a serious incident, but certificates can be issued with short validity periods (90 days) and rotated on a fixed schedule. Secrets are symmetric: if a secret is exposed in logs, code, or environment variables, it is immediately usable by anyone who has it. Store certificates in Azure Key Vault, reference them in the app registration, and rotate via Key Vault's certificate rotation policy. Never export certificate private keys to files.

Sources & references

  1. Microsoft Graph API Applications Resource
  2. Microsoft Entra App Registration Documentation
  3. Microsoft Graph PowerShell SDK
  4. CIS Microsoft Azure Foundations Benchmark

Free resources

25
Free download

Critical CVE Reference Card 2025–2026

25 actively exploited vulnerabilities with CVSS scores, exploit status, and patch availability. Print it, pin it, share it with your SOC team.

No spam. Unsubscribe anytime.

Free download

Ransomware Incident Response Playbook

Step-by-step 24-hour IR checklist covering detection, containment, eradication, and recovery. Built for SOC teams, IR leads, and CISOs.

No spam. Unsubscribe anytime.

Free newsletter

Get threat intel before your inbox does.

50,000+ security professionals read Decryption Digest for early warnings on zero-days, ransomware, and nation-state campaigns. Free, daily, no spam.

Unsubscribe anytime. We never sell your data.

Eric Bang
Author

Founder & Cybersecurity Evangelist, Decryption Digest

Cybersecurity professional with expertise in threat intelligence, vulnerability research, and enterprise security. Covers zero-days, ransomware, and nation-state operations for 50,000+ security professionals every morning.

Black Hat Giveaway

Win a $2,495 Black Hat pass.

Full-access to Black Hat USA 2026 in Las Vegas. Subscribe free to enter.

Joins Decryption Digest daily briefing. Unsubscribe anytime.

Giveaway: Black Hat USA 2026 Full-Access Pass ($2,495 value)

Details →
Daily Briefing

Subscribe to enter the giveaway

Every subscriber is automatically entered. You also get daily threat intel every morning: zero-days, ransomware, and nation-state campaigns. Free. No spam.

Already subscribed? You're already entered.

Giveaway

Win a $2,495 Black Hat USA 2026 pass.