How to Report Expiring Credentials for Entra ID Apps

Use the Microsoft Graph to Report App Credential Expiration Dates

A reader asks if it’s possible to notify administrators when app secrets expire or are close to expiring. App secrets (also called client secrets) are a mechanism to allow Entra ID registered applications to prove their identity and secure an access token to allow them to retrieve data. App secrets last between three and twenty-four months are not intended for production use. Instead, app secrets are a good way to test an application to make sure that it can access the right data using the right permissions before moving it from development to production.

An app can use both secrets and certificates (Figure 1). Both methods work, but once an application reaches production, it should move away from app secrets and use certificate-based authentication or, if the app runs as an Azure Automation runbook, a managed identity.

An Entra ID registered app can use both secrets and certificates to authenticate.
Figure 1: An Entra ID registered app can use both secrets and certificates to authenticate

Keeping track of expiring app secrets is a good idea. Developers might not have access to the app to replace an expired secret and have to ask an administrator to create a new secret. And if an app does get through into production while using app secrets, the check might reveal its existence and prompt developers to use a more secure authentication method.

Certificates do have expiration dates and are more likely to be used for production than app secrets, so paying attention to certificate expiration can be extremely important. Finally, it’s good to remove expired credentials from apps because once a credential expires, it becomes unusable debris. Being proactive and reviewing apps periodically helps to identify issues before they occur, which is always a positive thing to do.

Creating a Script to Report App Credential Expiration

The steps involved in creating a script to find applications and report their app credential expiration dates are straightforward. Here’s an outline.

  • Connect to the Graph endpoint with the Application.Read.All permission. If you want to email the report, the script uses the Mail.Send permission.
  • Run the Get-MgApplication cmdlet to find the set of registered apps. I usually reduce the set by only processing single-organization apps (the sign-in audience is “AzureADMyOrg”) and by removing the apps used by the SharePoint Framework to make calls to Graph APIs. The resulting set are those created by developers for use within the tenant.
  • For each credential, find its expiration date and report if it is expired, active, or about to expire (within 30 days of expiration).
  • Email the report to tenant administrators.

The PowerShell is relatively simple. The only oddity I found in the data is that some app secrets have expiration dates of 31-Dec-2299, which seems just a tad long (Figure 2 shows the excessively long-lasting expiration dates in an emailed report). While I can’t remember this, apparently it was possible to set expiration for an app secret to be “never” in the past, which results in the 2299 date. The Entra ID admin center doesn’t allow a never-expiring app secret now, and certainly no secret created since March 2021 has such an expiration. Never-expiring app secrets might be convenient for development purposes, but if you don’t like them, you can easily fix the problem by removing the secret and replacing it with a secret configured with a more reasonable expiration date. Any apps that use the deleted secret must be updated to use the new secret.

Email to administrators with information about app credential expiration dates/
Figure 2: Email to administrators with information about app credential expiration dates

Points About Retrieving App Credential Expiration Dates

By default, the Get-MgApplication cmdlet does not retrieve details of app secrets and credentials when it retrieves information for a registered app. To get this data, you must include the keyCredentials (certificates) and passwordCredentials (app secrets) properties in the set requested when running the cmdlet.

Microsoft’s documentation doesn’t explain this, so working things out took a little while and some experimentation with the Graph Explorer. Even the Graph X-Ray extension, which gives an insight into the Graph commands used by the Entra ID admin center to process objects, comes up with a blank when exposing the credentials for an application, but I got there in the end.

Run Periodic Checks to Make Sure that App Credentials Don’t Expire

I like to run jobs that check settings on a periodic basis using scheduled Azure Automation runbooks. The code for the script (downloadable from GitHub) is easily adapted to access the Graph witha managed identity. One advantage of using a runbook is that the script can send email from any account, unless RBAC for Applications restricts access to certain mailboxes, which is probably how things should be configured.


Learn more about how the Microsoft 365 applications and Entra ID really work on an ongoing basis by subscribing to the Office 365 for IT Pros eBook. Our monthly updates keep subscribers informed about what’s important across the Office 365 ecosystem.

9 Replies to “How to Report Expiring Credentials for Entra ID Apps”

  1. Very helpful script Tony thanks! I wasn’t aware App Certs are preferential to Client Secrets in production. Most of the App Vendors that integrate with EXO need to update their vendor technical setup documentation. I’ve not yet come across any that advocate the cert method.

  2. Hi Tony,

    I’m struggling with the script to add it to an runbook, i keep getting error like “The term ‘Connect-MgGraph’ is not recognized as a name of a cmdlet,”The term ‘Get-MgApplication’ is not recognized as a name of a cmdlet,”
    i’ve created a service principal with a secret and i’ve modified a little bit to use the token, but still won’t work.
    Local on Powershell is working but via AA with runbook not.

    Function Add-MessageRecipients {
    # Function to build an addressee list to send email
    [cmdletbinding()]
    Param(
    [array]$ListOfAddresses )
    ForEach ($SMTPAddress in $ListOfAddresses) {
    @{ emailAddress = @{address = $SMTPAddress}}
    }
    }

    $appClientId = “xxxxxxxx”
    $appClientSecret = “xxxxxxxx”
    $tenantId = “xxxxxxx

    $body = @{
    “grant_type” = “client_credentials”
    “client_id” = $appClientId
    “client_secret” = $appClientSecret
    “scope” = “https://graph.microsoft.com/.default”
    }

    $tokenResponse = Invoke-RestMethod -Uri “https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token” -Method POST -Body $body
    $AccessToken = $tokenResponse.access_token | ConvertTo-SecureString -AsPlainText -Force

    # Connect to Microsoft Graph using the GraphAPI token
    Connect-MgGraph -AccessToken $AccessToken

  3. After running and reviewing your script, I truly appreciate your efforts for our community.

    Out of curiosity, the if/else section after line 97 “Connect-MgGraph -Scopes ‘Application.Read.All’, ‘Mail.Send’ -NoWelcome” seems misplaced. The script exits before gathering the info for ‘$RegisteredApps’.

    Are lines 99-104 in the right location?

    Please advise.

    1. You might look at GitHub again. I’ve been working on that script to add the inclusion of app permissions in the emailed report (expect a post about this tomorrow) and code has been ‘shifting.’ I think a good version is now in place.

  4. Hi Tony,

    Thanks for another great article.

    Just out of curiosity wanted to ask if there is any reason that you are verifying only apps that are limited to the organization?
    I think that “AzureADMultipleOrgs” apps should be also considered.

    Regards,
    Marcin

    1. You can certainly change the filter to pick up any apps you want. I chose to focus on registered apps created in the tenant… just to show what’s possible.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.