Close Menu
Peter Klapwijk – In The Cloud 24-7Peter Klapwijk – In The Cloud 24-7
    Facebook X (Twitter) Instagram
    Peter Klapwijk – In The Cloud 24-7Peter Klapwijk – In The Cloud 24-7
    • Home
    • Intune
    • Windows
      • Modern Workplace
    • macOS
    • Android
    • iOS
    • Automation
      • Logic Apps
      • Intune Monitoring
      • GitHub
    • Security
      • Passwordless
      • Security
    • Speaking
    • About me
    Peter Klapwijk – In The Cloud 24-7Peter Klapwijk – In The Cloud 24-7
    Home»Automation»Get notified on expiring Azure App Registration client secrets
    Automation

    Get notified on expiring Azure App Registration client secrets

    Peter KlapwijkBy Peter KlapwijkJanuary 17, 2022Updated:February 14, 2025728 Mins Read

    Today another blog post that involves Logic Apps. I use some App Registrations in Azure, for example, to use in my Logic App flows. To authenticate with these App Registrations I use client secrets. But these client secrets expire once in a while which causes my flows to stop working if I don’t replace them before the expiring date. I would like to get a notification a few weeks before one of these secrets will expire, but I don’t see an out-of-the-box solution for this. So of course I came with the idea to solve this issue with a Logic Apps flow (again) as the information about the end date of the client secret is available via Graph API.

    The solution

    Via Graph API we’re able to get information on the App Registrations in our Azure tenant. This information holds the end date from the underlying client secret. The client secret information is available in an array. Because of that array, we need to initialize some variables to grab the required information to further process it in our flow. By using a condition in the flow, we can filter out the expiring client secrets based on the end date. We’re able to trigger a notification that can be sent via email or can be sent to a Teams channel.

    This is what the complete flow looks like.

    This flow monitors all App Registration client secrets. At the end of the post I briefly describe the extra steps which need to be taken to only monitor the App Registration of your choice.

    The complete flow can also be downloaded as an ARM Template from my GitHub repository.

    The requirements

    To get this logic Apps flow up and running we have a few requirements.

    Via an HTTP action, we’re going to query Graph API for the information we need. This HTTP uses an Azure App Registration, which is our first requirement. The App Registration is used for authentication in the HTTP actions and also for granting the required permissions.
    The minimum required permission for this Logic App is shown below:
    Application.Read.All

    To secure the HTTP action I use Azure Key Vault, which is described in this previous post. The Key Vault holds the client secret and keeps this secure in the flow. I also added the tenant id and client id to the vault, so I only have to query the Key vault for this information.
    This flow only uses one HTTP action, if you have several HTTP actions in a flow, in every HTTP action the tenant and client id needs to be added. By storing the information in a variable or in a Key Vault, we don’t have to copy/ paste the ids in every HTTP action.

    Depending on how you want to receive the notifications, permissions on a (shared) mailbox or a Teams webhook connector are needed.

    Setup the Logic Apps flow

    Let’s configure the Logic Apps flow.

    Sign in to the Azure portal and open the Logic App service. I created a blank Logic App of type Consumption.

    When the creation of the Logic App is finished, open the flow. A few templates are shown, choose Recurrence.

    The Logic App designer is opened and the recurrence trigger is added. Choose the recurrence settings of your choice. I choose to run the flow once a week.

    The first action we’re going to add is the Get secret action, which is an Azure Key Vault action. With this action, we retrieve the tenant id, which we use in the HTTP action.
    Search on Azure Key and select Get secret.

    Enter the name of the Vault and select your tenant. Next, click Sign in to authenticate to the Key Vault.

    Choose tenant id from the drop-down list.

    Repeat the Key Vault steps to also retrieve the client id and client secret.

    In the next action, we are going to initialize variables for appId, displayName, and passwordCredentials.
    Search for variables and select Initialize variable (three times).

    Enter a Name for the variables. For appId and displayName select type String. For passwordCredential select type Array.

    The next step we’re going to add is an HTTP Action, to query Graph for the App Registrations.

    Choose GET as Method.
    As URI enter:

    https://graph.microsoft.com/v1.0/applications?$select=id,appId,displayName,passwordCredentials

    With this select, we only select the items which are relevant to the information I want to use later in this flow. If you need more information, the URL needs to be expanded with that information.

    Choose Add new parameter and check Authentication. Select Active Directory OAuth as authentication type.
    As tenant, client id, and secret, we add the Dynamic content Value. Make sure you pick the value from the correct Key Vault action.
    Enter https://graph.microsoft.com as Audience.

    This is our HTTP action.

    To use the information we received (by executing this HTTP action) in the upcoming actions, we need to parse the received information with a Parse JSON action.

    Add a Parse JSON action to the flow.
    We’re going to parse the response body of the previous HTTP action. In the Content box, we add Body, from the previous HTTP action.

    To fill the schema with the correct information, we can add an example payload. The information to use as an example payload can be ‘generated’ by running the flow. Save the flow and hit Run trigger to start the flow.

    Open the Runs history from the flow and open the HTTP action. Copy the body.

    Click Use sample payload in the Parse JSON action, past the information which we copied from the runs history in the new pop-up, and click Done.

    This is our Parse JSON action.

    If you receive an error like “Invalid type. Expected string but got Null” you can simply resolve that by changing

    "type": "string"

    to

        "type": ["string", "null"]
    

    Next, we’re going to use Set variable actions to set the previously initialized variables.

    Add a Set variable action. Choose appId from the drop-down list. As value we add dynamic content appId from the Parse JSON action.

    This will automatically add the Set variable action in a For each action.

    Add two more Set variable actions and repeat the steps for displayName and passwordCredential.

    Add aother For each action, which is a Control action.
    As the output select passwordCredentials from the Parse JSON action.

    Add a Condition action, which is also a Control action. With this action, we’re going to determine if the end date of the secret (passwordCredential) falls between today and 14 days ago. If that’s true it is expiring and a follow up action is performed.

    To grab the end date from the passwordCredentials we need to use the below expression:

    items('For_each_passwordCredential')?['endDateTime']

    Replace For_each_passwordCredential with the name of your last added For each action and replace the spaces with an -. Add this expression in the left text box.

    Select is less than from the drop-down list.

    In the right text box enter the below expression to add the current date – 14 days:

    addToTime(utcNow(),14,'day')

    This is how our For each action looks like with the Condition action added.

    Under True, we need to add the action which sends us the notification. I choose to send an email from a shared mailbox.

    We can enter text, but also use data from previous actions in the body of the email.

    I used displayName from the Parse JSON action to display the App Registration name.

    And I used expressions to get information from the passwordCredential variable. These expressions are comparable to the expression used to get the end date of the secret. To use the key id, display name and end date of the secret (passwordCredential), use below expressions:

    items('For_each_passwordCredential')?['keyId']
    items('For_each_passwordCredential')?['displayName']
    items('For_each_passwordCredential')?['endDateTime']

    This is my email action under True, where I also added the URL to the App Registration for which I use the appId from the Parse JSON action.

    Thiss is our complete flow.

    Only monitor the App Registrations of your choice

    If you’re not responsible for all App Registrations, you might only want to monitor the secrets of the Apps for which you’re responsible. That’s also possible if we use the Object ID of the Apps in our HTTP Get action. In this example, I used a SharePoint List which holds the object IDs if the Apps that I want to monitor.

    In our flow, we need to add a SharePoint Get Items action to our flow. This action retrieves the items from the SharePoint list, which we can later use in the HTTP action as a variable.

    In our HTTP action, we use the dynamic content variable from the Get items action. This automatically adds the HTTP action in a For each action.

    As the HTTP action is already in a For each action, the first Set variable action doesn’t need to be added in another For each action. The first part of the flow looks like below.

    The end result

    The end result is pretty simple. We receive an email in our mailbox when a client secret is about to expire. And this is the email that I received from the Logic App, which contains information regarding the expiring client secret.

    That’s it for this blog post. I hope you find it helpful and you don’t let your secrets expire anymore 🙂

    Azure Azure AD Flow Graph Graph API Logic Apps Power Automate PowerApps
    Share. Facebook Twitter LinkedIn Email WhatsApp
    Peter Klapwijk
    • Website
    • X (Twitter)
    • LinkedIn

    Peter is a Security (Intune) MVP since 2020 and is working as Modern Workplace Engineer at Wortell in The Netherlands. He has more than 15 years of experience in IT, with a strong focus on Microsoft technologies like Microsoft Intune, Windows, and (low-code) automation.

    Related Posts

    Configure FIDO security keys as the default sign-in option for Windows

    February 27, 2023

    Windows Autopilot lifecycle automation with Logic Apps – Part2

    May 18, 2022

    Export Endpoint Analytics Proactive remediation data with Logic Apps

    April 19, 2021
    View 72 Comments

    72 Comments

    1. Dinesh on January 23, 2022 02:15

      Hi Peter,

      Thanks for the great article. I was falling with the following error message. “test connection failed. Error ‘REST API is not yet supported for this mailbox.” any idea how to troubleshoot?

      Thank you.

      Reply
    2. Peter Klapwijk on January 23, 2022 09:39

      Hi Dinesh,

      Are you using an Exchange Online shared mailbox?
      Have a look at this article https://docs.microsoft.com/en-us/exchange/troubleshoot/user-and-shared-mailboxes/rest-api-is-not-yet-supported-for-this-mailbox-error

      Reply
      • Dinesh on January 23, 2022 21:42

        Hi Peter,
        Thanks for sharing the article, I looked at the same article b4 but the shared mailbox that I use is on Exchange online. no On-premises integration at all.

        Tks

        Reply
    3. Neha on January 25, 2022 10:29

      Hi Peter,

      Can we get the details of secret expiration from AzureActiveDirectory—>App registartions

      Reply
      • Peter Klapwijk on January 25, 2022 10:54

        Hi Neha,

        These are the exact same App Registrations.

        Reply
        • Sarath on July 4, 2023 15:22

          Hi Peter,

          Can we get all in one email , rather getting emails for each and every secret.

          Reply
    4. Jack smith on January 26, 2022 06:03

      Awesome guide – i cant seem to use the parse json variables though in the email- what could cause that? All 3 set variables done in the

      ‘foreach appid’ section dont seem to be available.

      Reply
      • Peter Klapwijk on February 2, 2022 20:16

        You are not able to copy/ paste in the expression?
        You should use the For_each_passwordCredential. But if that For each action in your flow has a different name, that needs to be changed in the expression.
        Otherwise, use the ARM template which you can find on my GitHub Repo https://github.com/PeterKlapwijk/Microsoft-Logic-Apps/tree/main/Azure%20App%20Registration%20Client%20Secret%20Notification

        Reply
    5. Taj on February 2, 2022 19:51

      Hi Peter,

      We are getting alerts for only few app registrations client certificate expiry.
      for ex: if 5 app registration client certificate is getting expired in 1 week, we are getting alert for only 2 app registration. what could be the reason for the logic app to ignore other app registrations that also has client expiry in a week.

      Thanks
      Taj

      Reply
      • Peter Klapwijk on February 2, 2022 20:23

        Hi Taj,

        Use the Runs history to determine in which action it fails. In the variable display name under the first for each, you can see the names. So first determine with that variable if the App Registration is retrieved from the Graph. And if the passwordCredential is stored in the variable.
        If these are both retrieved, move on to the next action and determine if the Condition is true. Maybe the Azure portal shows the cert is about to expire, but it falls outside the 14 days of the condition (I’m not sure how many days before the cert is expiring it is shown in the portal). If that’s the case, change the number of 14 days to your own choice.

        Otherwise, use the ARM template which you can find on my GitHub Repo and see if that is of any help https://github.com/PeterKlapwijk/Microsoft-Logic-Apps/tree/main/Azure%20App%20Registration%20Client%20Secret%20Notification
        If tested this with 5 expiring certificates and that works as expected.

        Reply
        • Taj on February 3, 2022 10:12

          Hi Peter,

          Thanks for your support.

          We found the issue, we have around 350 App registration, but the logic app considers only 100 app registration. so it ignores the rest.
          so how could we increase the limit pf app registration in the logic app.

          Reply
          • Peter Klapwijk on February 3, 2022 10:31

            Hi Taj,

            Give this uri a try in the HTTP Action https://graph.microsoft.com/v1.0/applications?$top=400&$select=id,appId,displayName,passwordCredentials

            It holds top=400 which you can increase if needed.

            Reply
          • Marwane Jabbes on March 1, 2023 15:28

            Hey Taj,
            Have you found a solution for this issue? I got the same.

            Reply
    6. Bas. O on February 14, 2022 14:52

      Hi Peter,

      Fellow dutchman here.

      I am having some difficulties getting the solution to work fully.
      Everything seems to work except sending from the shared mailbox.

      I’ve autorised both api connections (Keyvault and (O365) but I am still getting the following error below. Could you send in the right direction?

      Thanks in advance!

      {
      “statusCode”: 404,
      “headers”: {
      “Pragma”: “no-cache”,
      “x-ms-request-id”: “62bd15e4-671f-f3ea-fe3b-840cddb5815c”,
      “Strict-Transport-Security”: “max-age=31536000; includeSubDomains”,
      “X-Content-Type-Options”: “nosniff”,
      “X-Frame-Options”: “DENY”,
      “Cache-Control”: “no-store, no-cache”,
      “Set-Cookie”: “ARRAffinity=034a92f9ba2fc4ecf4919720c4a64dda736d4b72182be442bf2b2ab6744078db;Path=/;HttpOnly;Secure;Domain=office365-we.azconn-we-01.p.azurewebsites.net,ARRAffinitySameSite=034a92f9ba2fc4ecf4919720c4a64dda736d4b72182be442bf2b2ab6744078db;Path=/;HttpOnly;SameSite=None;Secure;Domain=office365-we.azconn-we-01.p.azurewebsites.net”,
      “Timing-Allow-Origin”: “*”,
      “x-ms-apihub-cached-response”: “true”,
      “x-ms-apihub-obo”: “true”,
      “Date”: “Mon, 14 Feb 2022 13:44:26 GMT”,
      “Content-Length”: “676”,
      “Content-Type”: “application/json”,
      “Expires”: “-1”
      },
      “body”: {
      “status”: 404,
      “message”: “Specified folder not found. The error could potentially be caused by lack of access permissions. Please verify that you have full access to the mailbox.\r\nclientRequestId: *anonymised*\r\nserviceRequestId: *anonymised*”,
      “error”: {
      “message”: “Specified folder not found. The error could potentially be caused by lack of access permissions. Please verify that you have full access to the mailbox.”,
      “code”: “ErrorFolderNotFound”,
      “originalMessage”: “The specified folder could not be found in the store.”
      },
      “source”: “office365-we.azconn-we-01.p.azurewebsites.net”
      }
      }

      Reply
    7. Eric on March 10, 2022 14:57

      Hi Peter,
      thanks for publishing this great article. I wanted to download the ARM-template just now but in the repo for this solution is just the readme.md file and no ARM-template anymore?
      Regarding the managed-identity improvement that was made by Luise Freese, was that only done in the License-reporting logic-app that you have in github?

      I’ll try to setup the logic-app manually now. Thanks for sharing.

      Reply
      • Peter Klapwijk on March 10, 2022 17:11

        Hi Eric,

        Something did go wrong probably, but the azuredeploy.json is added back.
        The change from App registration to Managed Identity was done for the License reporting and Autopilot deployment event Logic Apps.
        If I have time, I’ll also change the others.

        Regards,

        Peter

        Reply
    8. Neha on March 24, 2022 14:57

      Hi Peter,

      I want to change my rest API email connection to a gmail account, please advise.

      Please check your account info and/or permissions and try again. Details: REST API is not yet supported for this mailbox. This error can occur for sandbox (test) accounts or for accounts that are on a dedicated (on-premise) mail server.

      Reply
      • Neha on March 24, 2022 15:29

        Hi Peter,

        I have added Sendmail V2 connection and the connection works fine now .
        The issue now is I’m getting individual email for each and every secret . Is there anyways to get all the list of expiring secrets for the current month in a single mail. So that the recipients get a view of all expired secrets of the current month or next 30 days .

        The below is the sample email I get , as well i get the secret list which expired in 2021 as well.

        Client secrets listed are about to expire.
        SPN-xxxxxx

        Details:
        Secret ID:0000000000000000
        Display Name:
        Expiration date:2021-11-16

        App registration location : 0000000-00000-00000000-000000000

        Please take necessary action.

        Reply
        • Fadi Matni on April 4, 2023 20:11

          Hi Neha ,

          i have the same issue did you get any response or solution ?
          thanks in advance

          Reply
        • Lovely on April 5, 2023 05:03

          Hello Neha, I’m getting the same issue. Did you solve this?

          Reply
    9. Chris on March 25, 2022 17:37

      Hello, thank you so much for info, this is great.
      I’m having a bit of challange, here is my JSON schema… I’m not getting “appID”, “displayName” as part of ParseJSON value when I try to set variable. ANy clue?

      {
      “properties”: {
      “@@odata.context”: { “type”: [“string”, “null”] },
      “value”: {
      “items”: {
      “properties”: {
      “appId”: { “type”: [“string”, “null”] },
      “displayName”: { “type”: [“string”, “null”] },
      “id”: { “type”: [“string”, “null”] },
      “passwordCredentials”: {
      “items”: {
      “properties”: {
      “customKeyIdentifier”: {},
      “displayName”: {},
      “endDateTime”: {
      “type”: [
      “string”,
      “null”
      ]
      },
      “hint”: {
      “type”: [
      “string”,
      “null”
      ]
      },
      “keyId”: {
      “type”: “string”
      },
      “secretText”: {},
      “startDateTime”: {
      “type”: [
      “string”,
      “null”
      ]
      }
      },
      “required”: [
      “customKeyIdentifier”,
      “displayName”,
      “endDateTime”,
      “hint”,
      “keyId”,
      “secretText”,
      “startDateTime”
      ],
      “type”: “object”
      },
      “type”: “array”
      }
      },
      “required”: [
      “id”,
      “appId”,
      “displayName”,
      “passwordCredentials”
      ],
      “type”: “object”
      },
      “type”: “array”
      }
      },
      “type”: “object”
      }

      Reply
      • Lovely on April 4, 2023 05:38

        Hi Chris. Did you already solve this? I’m experiencing the same issue.

        Reply
      • Lovely on April 5, 2023 05:15

        Hello Chris. I was able to get the value of appid and displayname in parse json by only adding this “type”: [
        “string”,
        “null”
        ]
        on this part.
        “passwordCredentials”: {
        “items”: {
        “properties”: {
        “customKeyIdentifier”: {},
        “displayName”: {},
        “endDateTime”: {
        “type”: [
        “string”,
        “null”
        ]

        Reply
    10. Steve on April 6, 2022 16:22

      Hi Peter
      I am trying to implement this in our tenant but the run always fails at the For_each_appid step with the very helpful error {“code”:”ActionFailed”,”message”:”An action failed. No dependent actions succeeded.”}
      Not quite sure where to start looking. As far as I can tell all the components are setup correctly.
      Any ideas?

      Reply
      • Andy on May 9, 2022 19:18

        I am getting this as well. Did you ever find a fix? I can see that I have secrets expiring but they are not alerting.

        Reply
        • Andy on May 12, 2022 20:03

          If it helps anyone I got the {“code”:”ActionFailed”,”message”:”An action failed. No dependent actions succeeded.”} fixed. It was a permissions issue on the shared mailbox. I had to change the connection to Exchange to use my account and grant Send on Behalf

          Reply
    11. James on May 4, 2022 17:09

      Great guide so far, I am new to Logic apps so has been very useful.

      Currently stuck, I am running the logic app to generate the example payload for the Parse JSON and the HTTP is coming back with the error;
      Forbidden
      “code”: “Authorization_RequestDenied”,
      “message”: “Insufficient privileges to complete the operation.”,

      I have checked the tenant, client, and secret fields are all using the correct key vault entries and that the App registration has the permission of;

      Application.Read.All
      User.Read

      And admin consent is given.

      Are there any other permissions that need to be included that I am missing, would love to get this working for us? Appreciate if anyone or Peter could let me know. Cheers!

      Reply
      • Shadee on June 14, 2022 14:00

        Make sure that the Application.Read.All type is not Delegated. Should be Application.

        Reply
    12. Neha on May 9, 2022 11:09

      Hi Peter,

      Can we get all in one email , rather getting emails for each and every secret.

      Reply
    13. Marco Schilder on May 12, 2022 08:19

      I’ve deployed the ARM template in a test environment with 116 App Registrations, with 8 expired secrets and 2 that are about to expire in 1 week. The flow runs successful, and I receive 2 emails. The layout is as follows:

      One of the client secrets is going to expire from Azure App Registration;
      APP-01
      APP-02

      Details:
      Secret ID: 1234-ahdbc-hjsdjdsj-12234
      Display Name:
      Expiration date: 2021-11-05T09:04:13.0006862Z

      App Registration location;
      https://portal.azure.com/#blade/Microsoft_AAD_RegisteredApps/ApplicationMenuBlade/Overview/appId/
      1234-ahdbc-hjsdjdsj-12236
      1234-ahdbc-hjsdjdsj-12237

      Please take action as soon as possible.

      So the email notifies me about 2 App ID’s, 1 that is in fact expired and 1 that is ok? Then the next email that also notifies me about another App ID that is expired and 1 that is ok. So 2 emails, 4 App ID’s and 2 expired. That still leaves 6 expired behind and the 2 that about to.

      As a test, I ran it a couple of times. The 2 that are expired still come back in the 2 emails, along with 2 random app ID’s that are ok. I thought maybe there is a limit to the email, so I fixed the 2 expired App ID’s. Ran the flow again, now no emails. Not sure how to troubleshoot this?

      Reply
    14. Sukh on May 23, 2022 09:03

      Hi All,

      I user ARM template to create Flow. but I’am getting the below error message.
      “status”: 404,
      “message”: “Operation failed because the requested resource was not found in the key vault.\r\nclientRequestId: 05f68bdf-c3a3-4028-b84a-a18c3db1fe3d”,
      “error”: {
      “message”: “Operation failed because the requested resource was not found in the key vault.”
      },
      “source”: “keyvault-ae.azconn-ae-001.p.azurewebsites.net”
      }
      Can anyone please help

      Reply
    15. Bruce Shi on June 21, 2022 06:16

      Hi Peter,
      Thank you very much for the great article. I tried to run, but failed at step ‘HTTP Get Azure Applications’, the error message is as below.please kindly help to advise.thanks
      ===
      error”: {
      “code”: “Authorization_RequestDenied”,
      “message”: “Insufficient privileges to complete the operation.”,
      “innerError”: {
      “date”: “2022-06-21T04:09:11”,
      “request-id”: “a6735ab5-e5ca-49f7-8889-8f4a0ca15d59”,
      “client-request-id”: “a6735ab5-e5ca-49f7-8889-8f4a0ca15d59”

      ===

      Reply
      • Peter Klapwijk on June 26, 2022 09:30

        Hi Bruce,

        The message indicates the account/ identity which is used for this action doesn’t have the required permissions. So have a look at the permissions of the account. If the permissions were just recently assigned, give it another try some later, as it can take some time before newly assigned permissions are active.

        Regards,

        Peter

        Reply
    16. Ram on July 10, 2022 09:55

      Hi Peter,

      The script works fine , thank you so much for this great article.
      Can we just send emails only to app owners stating that the app registration secret is gonna expire

      Reply
      • Lovely on April 5, 2023 05:16

        Hi Ram. Did you find a solution to this? I also plan to do the same.

        Reply
    17. Garry on July 20, 2022 11:16

      Hi Peter,

      Thanks for the great article. My company hosts application servers in Azure on behalf of clients. The application servers use an app client ID and secret to look up info from the customer’s Azure AD tenant (e.g. to list users). We do not have any other access to the client’s AAD tenant.

      We only want to monitor the expiration date for the app client secret that the client has given us. Your article says that your Logic App needs to use a separate/dedicated app registration that has the “Application.Read.All” permission assigned. However, we do not want to enumrate all app registration secret expiration information, only the expiration date for the app secret that they have assigned to us. Is this possible (does an app have the permission required to read it’s own client expiration date?)

      Reply
      • Garry on July 25, 2022 15:04

        To answer my own question: no, the app registration that we are working with does not have permission to read its own client secret expiration date(s). It is possible to connect using the following:

        $pscredential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $AppId, $AppSecret

        Connect-AzAccount -ServicePrincipal -Credential $pscredential -Tenant $tenantId

        But any attempt to run Get-AzADAppCredential, Get-AzADServicePrincipal, Get-AzADApplication, Get-AzADAppPermission or Get-AzADSpCredential focused on the app’s own object all result in the error “Insufficient privileges to complete the operation”. Same deal using Microsoft Graph.

        Reply
    18. John Amorim on September 2, 2022 17:44

      Hi Peter,
      Great Article… unfortunately I stuck in one part that couldn’t find exactly the solution..

      ”
      ExpressionEvaluationFailed. The execution of template action ‘For_each_passwordCredential’ failed: the result of the evaluation of ‘foreach’ expression ‘ @{items(‘For_each_appId’)?[‘passwordCredentials’]}’ is of type ‘String’. The result must be a valid array.
      ”

      Any idea on what can be done to resolve it ?

      Thanks

      Reply
      • Mike on October 12, 2022 21:42

        I was getting this error also when I created the app manually. I had tried modifying the code as there was a definition of passwordCredential listed as “string” but that didn’t work.

        I was able to get past it by using the JSON template provided and using that to create the app.

        Reply
    19. Liju P Nandanan on September 27, 2022 12:36

      Hi Peter,
      I am getting the following error. Bit I have provided the access in api permissions. I am able to get the details directly with graph api url. But through the flow I am getting this error
      BadRequest. Http request failed as there is an error getting AD OAuth token: ‘AADSTS700016: Application with identifier ‘8213a9c7-eb18-4e31-abba-608c7fe1568f’ was not found in the directory ‘Default Directory’. This can happen if the application has not been installed by the administrator of the tenant or consented to by any user in the tenant. You may have sent your authentication request to the wrong tenant. Trace ID: a090ca62-7358-4bd9-93b9-b1a4285f1b00 Correlation ID: 7fcfaf9b-d5b2-4f6f-aaca-1eacbd69bcdb Timestamp: 2022-09-27 10:30:39Z’.

      Reply
      • Mike on October 12, 2022 21:40

        I was getting this error also when I created the app manually. I was able to get past it by using the JSON template provided and using that to create the app.

        Reply
    20. Fabian on September 29, 2022 11:59

      I run in to the same error als Liju P, BadRequest. Http request failed as there is an error getting AD OAuth token: ‘AADSTS700016: Application with identifier ‘2740699a-b6c6-4932-93fc-6c53ea1d8665’ was not found in the directory ‘ORTEC Finance’. This can happen if the application has not been installed by the administrator of the tenant or consented to by any user in the tenant. You may have sent your authentication request to the wrong tenant.

      Reply
      • Fabian on September 30, 2022 11:20

        Was using the wrong field for client id, this must be the application id.

        Reply
    21. Henic Appelgren on September 30, 2022 11:14

      Hi Peter,

      Thanks for this great article! I got it up and running without any issues!

      Is there a simple way to add fetch the Owner of the App registration and use that value as the recipient of the mail?

      Thanks!

      Reply
      • Lovely on April 5, 2023 05:22

        Hi Henic. Did you get the solution to this?

        Reply
    22. Jay W on October 11, 2022 02:23

      Hello bit of noob question, when importing the azuredeploy.json template into the custom deployment template editor getting an error at the very first tag stating that “Expected a JSON object, array or literal.json(0)” and as result can’t save the file. I attempted to address this by modifying the formatting without any luck. Thoughts on how to address this.

      Reply
    23. Allen on October 14, 2022 12:01

      Hi Peter,
      Thanks for your support.

      Is there any way we can get the app registration name in output, rather than secret name?

      Reply
    24. Russ Rimmerman on November 28, 2022 23:22

      Seems so similar to mine 🙂 https://techcommunity.microsoft.com/t5/core-infrastructure-and-security/use-azure-logic-apps-to-notify-of-pending-aad-application-client/ba-p/3014603

      Reply
    25. Guru on December 1, 2022 10:17

      I am getting email but only with the below text message. not getting the App details.

      One of the client secret is going to expiry
      Details:
      Secret ID:
      Display Name:
      Expiration date:

      Reply
    26. Lil on March 3, 2023 09:41

      Hello,
      It would be better if all setup was explained step by step, else for users who are not very familiar with the things it is complex to understand what should be added where.

      Reply
    27. VitusQ on March 6, 2023 21:28

      when you mention the statement “I also added the tenant id and client id to the vault, so I only have to query the Key vault for this information” – how is this to be done?

      Reply
    28. VitusQ on March 7, 2023 00:14

      How to add remaining number of days variable to the email notification?

      Reply
    29. Fadi Matni on April 4, 2023 20:01

      Hi Peter ,

      thanks for this article it woks fine but i have few apps that already expired since like years so i’m receiving each timne 20 emails with those Apps i only need starting from year 2023 with close to 14 days expiration , it is possible ?

      Reply
    30. Lovely on April 5, 2023 05:27

      Hi Peter.
      The script works fine and thank you very much for your article. But I also have a few questions.
      Can we just send emails only to app owners stating that the app registration secret is gonna expire?
      And for second question.
      I’m receiving the notification from my own email. Can we just a custom sender for this?
      Lastly,
      Can we just separate the already-expired secrets and the nearly-expired secrets?

      Thank you in advance for your response.
      Have a great day.

      Reply
      • Fadi Matni on April 5, 2023 21:32

        Hi Lovely ,
        for youe first question in my case some APP don’t have an owner so probably it will not work
        for the second question for the already expired secrets i tried to modify the addtotime expression didn’t work so what i end up doing as workaround by deleting the expired Secret from Apps and now i’m getting only the one that expire in 14 days only
        hope we have an fix for that from peter but that’s my work arround 😉
        thanks

        Reply
        • mikelarch on September 15, 2023 08:41

          Hello Fadi,

          May I ask what did you do on those apps that have no owner?

          Reply
      • Fadi Matni on April 5, 2023 23:16

        Hi Lovely ,
        finally i found the solution for the already-expired secrets to elimninite those from receiving email you need to add in your Condition section for each paswordCredential another AND like :
        the first one is with : AND : endDatetime is greater expresion: utcnow()
        and you add another one with AND : endDatetime is less than expression: addToTime(utcNow(), 14, ‘day’)

        it works for me i don’t reveive anymnore the certicate already expired

        Reply
        • Fadi Matni on April 5, 2023 23:26

          few correction to my previous post
          the first one is : AND endDatetime is greater than with expression: utcnow()
          the second one is :AND endDatetime is less than with expression : addToTime(utcNow(), 14, ‘day’)

          Reply
          • Lovely on April 13, 2023 05:45

            Hello Fadi,

            Will try those suggestions. Thank you very much for answering my queries. 🙂

            Reply
    31. Fadi Matni on April 19, 2023 02:19

      Hi Peter ,

      thanks again i was able to do it for Enterprise Application (SPN) for SAML Certificate Expiration date change few Variable for keycredentiala instead of passwordcredentials
      and changed the URI for Graph API :
      https://graph.microsoft.com/v1.0/servicePrincipals?$top=100&$select=id,appid,Displayname,KeyCredentials

      Thanks again 😉

      Reply
    32. Drew on July 13, 2023 19:04

      Great article! Thank you for providing this. I was able to complete the steps successfully.

      Reply
    33. Jason on July 24, 2023 20:58

      Peter,

      I’m having issues with getting the endDatetime step, I put in the expression you show, but in the next screenshot it appears to be a variable from somewhere. I didn’t see in any of it where the then endDatetime variable was setup.

      Reply
    34. teach123 on August 15, 2023 22:20

      Hi Peter,

      Can we send email to Azure App Application owners?

      Thanks in advance!!

      Reply
      • mikelarch on August 25, 2023 05:54

        Hi teach123,

        Did you get any solutions for this?

        Thank you!

        Reply
    35. tharma Aravinthan on August 22, 2023 18:50

      I have 425 App registration in our Azure tenant and How do I add pagination as it is returning only 100 App registrations. I am getting Odata next link for next 100 records.Is there is a way to add paging concept in power automate http call.

      Reply
    36. Omar on September 25, 2023 21:51

      @Fadi Matni says:

      Can you share where you made those change specifically? I’m trying to use this logic app specifically for Enterprise Applications SAML Expiration. Thanks

      Reply
    37. Sravs on November 15, 2023 17:31

      Hi,

      In the example you shared is something for storing secret value in vault. But in our case we don’t know the value

      We are looking for something like notify via mail with client secrets expiring in 30days for all the apps in tenant in a csv file and it should run everyday and send out a mail

      Note- i have many app registrations in tenant and i don’t know secret value

      Reply
    38. Edwin Brouwer on April 9, 2024 10:59

      Hi Peter as always great blog and solution. We have over 1400 app registration and the maximum through the graph is 999. is there a easy way to bypass this?

      Reply
      • Peter Klapwijk on April 9, 2024 16:49

        Hi Edwin,

        What you can try is enable Pagination on the HTTP action that queries for the App Registrations. It’s found in the settings of the action, via the three dots.

        Reply
    39. Vikas Jain on October 18, 2024 20:06

      Hello Peter,

      I am getting this error when setting up the appid variable. Can you please hep on this.

      Workflow validation failed:
      inputs of workflow run action ‘Set_variable_appid’ of type ‘SetVariable’ are not valid. Self reference is not supported when updating the value of variable ‘appId’

      Reply
      • Vikas Jain on October 21, 2024 19:33

        Hi Peter, Any update here would be really highly appreciated. I am stuck and can not move forward.

        Reply
    40. Adam on May 29, 2025 17:31

      Hi there, I’ve noticed that app registrations that were created after the creation of the logic app are not picked up by the reminder. Any idea why that might be happening? We’ve had some expirations missed because of this.

      Reply
    Leave A Reply Cancel Reply

    Peter Klapwijk

    Hi! Welcome to my blog post.
    I hope you enjoy reading my articles.

    Hit the About Me button to get in contact with me or leave a comment.

    Awards
    Sponsor
    Latest Posts

    Create deployment ring groups for Microsoft Intune

    June 27, 2025

    Update Windows Defender during Windows Autopilot enrollments

    May 16, 2025

    Hide the “Turn on an ad privacy feature” pop-up in Chrome with Microsoft Intune

    April 19, 2025

    How to set Google as default search provider with Microsoft Intune

    April 18, 2025
    follow me
    • Twitter 4.8K
    • LinkedIn 6.1K
    • YouTube
    • Bluesky 1.5K
    Tags
    Administrative Templates Android Automation Autopilot Azure Azure AD Browser Conditional Access Edge EMS Exchange Online Feitian FIDO2 Flow Google Chrome Graph Graph API Identity Management Intune Intune Monitoring iOS KIOSK Logic Apps macOS MEM MEMMonitoring Microsoft 365 Microsoft Edge Microsoft Endpoint Manager Modern Workplace Office 365 OneDrive for Business Outlook Passwordless PowerApps Power Automate Security SharePoint Online Teams Windows Windows 10 Windows10 Windows 11 Windows Autopilot Windows Update
    Copy right

    This information is provided “AS IS” with no warranties, confers no rights and is not supported by the authors, or In The Cloud 24-7.

     

    Copyright © 2025 by In The Cloud 24-7/ Peter Klapwijk. All rights reserved, No part of the information on this web site may be reproduced or posted in any form or by any means without the prior written permission of the publisher.

    Shorthand; Don’t pass off my work as yours, it’s not nice.

    Recent Comments
    • Parth Savjadiya on Using Visual Studio with Microsoft Endpoint Privilege Management, some notes
    • Chris Johnson on Assign Deny Local Log On user right to an (Azure) AD group by using Microsoft Intune
    • Northernsky on Automatically wipe a Windows 10 device after a number of authentication failures
    • Henrik on Intune Driver update for Windows – Get applicable devices
    • Adam on Get notified on expiring Azure App Registration client secrets
    most popular

    Application installation issues; Download pending

    October 1, 2024

    Restrict which users can logon into a Windows 10 device with Microsoft Intune

    April 11, 2020

    How to change the Windows 11 language with Intune

    November 11, 2022

    Update Microsoft Edge during Windows Autopilot enrollments

    July 9, 2024
    Peter Klapwijk – In The Cloud 24-7
    X (Twitter) LinkedIn YouTube RSS Bluesky
    © 2025 ThemeSphere. Designed by ThemeSphere.

    Type above and press Enter to search. Press Esc to cancel.

    Manage Cookie Consent
    To provide the best experiences, we use technologies like cookies to store and/or access device information. Consenting to these technologies will allow us to process data such as browsing behavior or unique IDs on this site. Not consenting or withdrawing consent, may adversely affect certain features and functions.
    Functional Always active
    The technical storage or access is strictly necessary for the legitimate purpose of enabling the use of a specific service explicitly requested by the subscriber or user, or for the sole purpose of carrying out the transmission of a communication over an electronic communications network.
    Preferences
    The technical storage or access is necessary for the legitimate purpose of storing preferences that are not requested by the subscriber or user.
    Statistics
    The technical storage or access that is used exclusively for statistical purposes. The technical storage or access that is used exclusively for anonymous statistical purposes. Without a subpoena, voluntary compliance on the part of your Internet Service Provider, or additional records from a third party, information stored or retrieved for this purpose alone cannot usually be used to identify you.
    Marketing
    The technical storage or access is required to create user profiles to send advertising, or to track the user on a website or across several websites for similar marketing purposes.
    Manage options Manage services Manage {vendor_count} vendors Read more about these purposes
    View preferences
    {title} {title} {title}