๐ก๏ธ Recipe ยท Security & Compliance
Audit Entra ID App Registrations for Expiring Secrets/Certificates and Privileged Permissions
Identify app registrations with credentials expiring soon and flag privileged service principals that are unused or stale
Complexity
Advanced
Impact
security + compliance + identity + privileged-access + credential-management + audit
Context
Why This Matters
Entra ID (Azure AD) app registrations are a common source of security incidents and outages. Client secrets and certificates silently expire โ breaking backup jobs, line-of-business integrations, and SSO โ while abandoned apps with directory roles like Global Administrator provide a persistent, often forgotten attack path.
This recipe helps you perform a regular audit that answers two questions:
- Which app registrations have client secrets or certificates expiring in the next 30 days that need rotation before they cause an outage?
- Which apps hold privileged directory roles (Global Administrator and similar) and have not been used recently, making them candidates for removal or role reduction?
Run this monthly, or as part of quarterly access reviews, tenant hardening projects, or after an ownership change (e.g., an admin leaves the organization).
Expected Outcomes
After running this recipe you will have:
- A full inventory of app registrations with any client secret or certificate expiring within 30 days, including the hint/thumbprint and expiry date.
- A list of apps whose service principals are assigned the Global Administrator role (or other privileged roles you target) together with their last sign-in activity.
- Flagged candidates for credential rotation and for role reduction or deletion.
- A repeatable process you can schedule (for example, weekly) and feed into a ticketing system or notification channel.
Risks & Considerations
Warnings and gotchas
- Do not delete unknown apps. Many Microsoft first-party and third-party SaaS connectors appear in app registrations or enterprise applications. Confirm ownership before removing credentials or roles.
- Rotating a secret breaks the consumer. Coordinate with the app owner before invalidating a credential โ generate the new secret, hand it over, and only remove the old one once the consumer has switched.
- signInActivity requires AuditLog.Read.All and an Entra ID P1/P2 license. Tenants without this data should treat "unknown last sign-in" as "needs manual review," not "safe to remove."
- Global Administrator on a service principal is almost always wrong. Apps should use the least-privileged application permission they need. If you find one, investigate how it was granted (often via admin consent on a legacy app) and look for non-human-readable names which can be a compromise indicator.
- Federated credentials (workload identity federation) do not expire like secrets or certs โ the audit should not treat missing
endDateTimeas a finding. - Auditing is read-only; mitigation (rotating or removing credentials) is a separate change that must follow your normal change control.
Required Permissions
| Permission | Why It's Needed |
|---|---|
| Application.Read.All | List all app registrations and read their passwordCredentials and keyCredentials |
| Directory.Read.All | Read service principals and directory role assignments |
| RoleManagement.Read.Directory | Enumerate directory role assignments to identify privileged apps |
| AuditLog.Read.All | Read signInActivity on service principals to determine recent use |
The fastest way to get this done: just ask Dex. Copy the prompt below and paste it into your Dex conversation.
For IT Admins
Paste into Dex Pro
Audit expiring credentials and privileged apps via the Entra admin portal
This GUI-based walkthrough is useful for spot checks or when you need to act on a single finding. For a full tenant audit, the script or API approach is far more efficient.
Part 1 โ Find expiring secrets and certificates
- Sign in to the Microsoft Entra admin center as an account with Application Administrator or Global Reader.
- Navigate to .
- Select the All applications tab so you are not limited to apps you own.
- Click Columns and enable the Certificates & secrets column if available, or review each app individually.
- For each app, open it and go to . Note any Client secrets or Certificates with an Expires date within 30 days.
- Record the app name, the credential hint/thumbprint, and the expiry date in your tracker.
Part 2 โ Find apps with Global Administrator (or other privileged roles)
- In the Entra admin center, go to .
- Open the Global Administrator role.
- Review the Assignments tab. Assignments whose Type is Service Principal (not User or Group) are the apps you care about.
- Click each service principal to open its overview, then go to (or review the Sign-in activity column) to see when the app last authenticated.
- Flag any service principal whose last sign-in is older than 90 days, or which has never signed in.
- Repeat for other high-privilege roles you care about: Privileged Role Administrator, Application Administrator, Cloud Application Administrator, Privileged Authentication Administrator, User Administrator, Exchange Administrator, SharePoint Administrator.
Part 3 โ Triage findings
- For expiring credentials: contact the app owner and coordinate a rotation before the expiry date.
- For inactive privileged apps: confirm with the owner whether the role is still required; if not, remove the role assignment or delete the app.
Audit via Microsoft Graph
The audit requires cross-referencing three Graph collections: applications (for credentials), servicePrincipals (for sign-in activity), and roleManagement/directory/roleAssignments (for privileged role holders).
Step 1 โ List all app registrations with credentials
GET https://graph.microsoft.com/v1.0/applications?$select=id,displayName,appId,passwordCredentials,keyCredentials&$top=999Follow @odata.nextLink until all pages are consumed. Each app's passwordCredentials[] and keyCredentials[] contain an endDateTime field in ISO 8601 format.
Step 2 โ Enumerate Global Administrator assignments
Global Administrator has the well-known template ID 62e90394-69f5-4237-9190-012177145e10:
GET https://graph.microsoft.com/v1.0/roleManagement/directory/roleAssignments?$filter=roleDefinitionId eq '62e90394-69f5-4237-9190-012177145e10'Each result contains a principalId. Collect them into a set; any service principal whose id is in that set has Global Administrator.
Step 3 โ Fetch service principals with sign-in activity
GET https://graph.microsoft.com/beta/servicePrincipals?$select=id,appId,displayName,signInActivitysignInActivity.lastSignInDateTime is only populated when the app has signed in during the audit log retention window and requires AuditLog.Read.All plus Entra ID P1/P2.
Step 4 โ Correlate and report
Build a dictionary of service principals keyed by appId. For each application:
- Walk
passwordCredentialsandkeyCredentials; report any whoseendDateTimeis within the next 30 days and still in the future. - Look up the matching service principal and check whether its
idis in the Global Admin set. If so, evaluatesignInActivity.lastSignInDateTime; flag if older than 90 days or absent.
Example finding shape
{
"expiringSoon": [
{ "appName": "veeambackup", "type": "Secret", "expiry": "2026-03-19T00:00:00Z" }
],
"flaggedPrivilegedApps": [
{ "appName": "Legacy Provisioning Tool", "role": "Global Administrator", "lastSignIn": "2024-08-02T11:14:00Z" }
]
}Audit via Microsoft Graph PowerShell
The script below uses the Microsoft.Graph PowerShell SDK to run the complete audit and emit a CSV report. Install the modules once with:
Install-Module Microsoft.Graph.Applications,Microsoft.Graph.Identity.DirectoryManagement,Microsoft.Graph.Identity.SignIns -Scope CurrentUserThen authenticate with the required scopes:
Connect-MgGraph -Scopes "Application.Read.All","Directory.Read.All","RoleManagement.Read.Directory","AuditLog.Read.All"The script will:
- Page through every app registration and check both
PasswordCredentialsandKeyCredentialsfor expiry within the configurable window (default 30 days). - Enumerate role assignments for a configurable set of privileged directory roles (default: Global Administrator).
- Pull
signInActivityfrom the beta service principal endpoint and flag any privileged app inactive beyond the configured threshold (default 90 days). - Write two CSV files and print a summary to the console.
Run it on a schedule (Azure Automation, Task Scheduler, or a pipeline) and feed the CSVs into your ticket system or a Teams webhook for follow-up.
Next steps