Azure AD app registration secrets: a quick script to check who expires soon

When setting Azure AD app registration for using OAUTH 2 authentication, you need to create a client secret:

A client secret has an expiration date that now (from the Azure Portal) can be set to 24 months as maximum:

The option “Never” (for creating a secret that never expires) is disappeared from the UI for security reasons and Microsoft doesn’t want that you create secrets with an unlimited expiration date.

To be more clear, at the time of writing this post it could be possible to create a secret that expires after more than 2 years directly with Powershell with something like the following:

$startDate = Get-Date
$endDate = $startDate.AddYears(99)
$aadAppsecret01 = New-AzureADApplicationPasswordCredential -ObjectId YOURAPPID -StartDate $startDate -EndDate $endDate -CustomKeyIdentifier YOURSECRETNAME

but I cannot guarantee how long this will be supported. Microsoft was quite clear on this:

There are plans to limit lifetimes of the secret administratively. However, there are no current timelines or ETAs of when this will happen. Removing the UX option to have never expiring secrets is a first step of that process (you can still create secrets that never expire with PowerShell, AZ CLI and Graph API).

Obviously, a secret that expires could have a serious impact on your working applications. So, how you can monitor the expiration of your client secrets? This was a question that many partners (also internally) have raised to me recently.

Unfortunately, there’s not (at the moment) a native Microsoft’s features that sends an alert when a secret expires, so you need to create your own checks.

A possible solution could be to use Graph APIs and getting informations on your App Registrations in your Azure tenant by using a timer triggered Azure Logic Apps that sends an email with the secret that expires.

But if you want a more quick and easy solution, here there’s a Powershell script for doing that:

#secret expiration date filter (for example 30 days)
$LimitExpirationDays = 30

#Retrieving the list of secrets that expires in the above range of days
$SecretsToExpire = Get-AzureADApplication -All:$true | ForEach-Object {
    $app = $_
        Get-AzureADApplicationPasswordCredential -ObjectId $_.ObjectId
        Get-AzureADApplicationKeyCredential -ObjectId $_.ObjectId
    ) | Where-Object {
        $_.EndDate -lt (Get-Date).AddDays($LimitExpirationDays)
    } | ForEach-Object {
        $id = "Not set"
        if($_.CustomKeyIdentifier) {
            $id = [System.Text.Encoding]::UTF8.GetString($_.CustomKeyIdentifier)
        [PSCustomObject] @{
            App = $app.DisplayName
            ObjectID = $app.ObjectId
            AppId = $app.AppId
            Type = $_.GetType().name
            KeyIdentifier = $id
            EndDate = $_.EndDate

#Printing the list of secrets that are near to expire
if($SecretsToExpire.Count -EQ 0) {
    Write-Output "No secrets found that will expire in this range"
else {
    Write-Output "Secrets that will expire in this range:"
    Write-Output $SecretsToExpire.Count
    Write-Output $SecretsToExpire

This script permits you to select a number of days until your secret expires (for example, I want to retrieve all my secrets that expires in the next 30 days), it retrieves the secret details from your Azure AD app registrations and lists the secrets that are near to expire.

The output will be something like the following:

You can execute this script on a Runbook, send the results via email and much more (this is totally up to you). The goal of this post is just for saying that you need to consider this check into your set of admin tasks for your tenants, and here you have a quick and simple possible solution.

The complete script is available on my Github repo here.

1 Comment

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

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