A client secret expiry notice landed in our inbox recently, and what should have been a five minute renewal turned into a proper archaeology exercise.
The environment had a handful of Application Users sitting in the Power Platform admin centre with names like D365 Integration User and Dynamics Connect. Perfectly sensible names, except nobody currently on the team could say what they were actually connected to. No documentation, no runbook, no owner listed anywhere. Just an app registration in Entra ID with a secret ticking down towards expiry.
The obvious problem: if you rotate a secret without knowing what consumes it, you find out what consumes it the hard way, usually at the worst possible time. And if you leave it alone, the integration breaks anyway when the secret expires.
So the question became: how do you work out where an Application User is being used inside Dynamics 365 when there is nothing external telling you?
Why the Admin Centre Doesn't Help Here
The first place I looked was the Application Users list in the Power Platform admin centre. You get the name, the Application ID, the security roles assigned, and the status. What you don't get is any indication of what the app registration is actually doing at runtime.
Application Users are just service principals authenticating against Dataverse. Dataverse itself has no concept of "this integration is called X and it syncs Y". From the platform's point of view, there is simply a systemuser record that happens to be flagged as an application user, and it creates and updates rows like any other user would.
That last part turned out to be the way in. If the Application User has been writing to Dataverse, it has left fingerprints in the createdby and modifiedby columns of whatever tables it touches. Work out which tables those are, and you can usually reverse engineer what the integration does.
There are two practical ways to find those fingerprints.
Option 1: Audit Summary View
If auditing is enabled in the environment, this is the cleanest approach, because it filters specifically on the operation type rather than just matching a value anywhere.
Step 1: Confirm auditing is actually on
Go to the Power Platform admin centre, select your environment, then Settings > Audit and logs > Audit settings. Check that Start Auditing is ticked at the environment level.
This is the catch with this approach. Auditing is not retrospective. If it was only switched on last month and the integration has been running for two years, you will only see the last month of activity. That is usually still enough to identify the tables, but it is worth knowing before you draw conclusions from an empty result.
Step 2: Open the Audit Summary View
From the same environment, go to Settings > Audit and logs > Audit summary view. This opens the classic audit grid showing every audited operation across the environment in one list, rather than the per-record Audit History tab you get on a form.
Step 3: Filter by the Application User
Use the filter on the Changed By column and select the Application User you are investigating. The application users appear in this list the same way normal users do, since they are systemuser records underneath.
Step 4: Filter the operation to Create
Filter the Operation column to Create. This is the important step. Filtering on Create rather than Update tells you which tables the integration is genuinely populating, as opposed to tables where it is only touching existing records or where it happens to be the last person to have modified something.
If you want a fuller picture, run it a second time with Update to catch tables the integration writes to but doesn't create rows in. An integration that only updates existing Contacts, for example, would be invisible if you only looked at Create.
Step 5: Read the Record Type column
The Record Type column now gives you the list of tables that Application User has been writing to. That is your answer. From there it is usually a short hop to identifying the integration, since the combination of tables is normally quite distinctive. A set of Account, Contact and Opportunity rows suggests something quite different from a set of custom staging tables or Case records.
Step 6: Export if the volume is large
If the result set is big, use the export to Excel option on the grid so you can pivot the results by Record Type and get a clean count per table. Seeing that one Application User created 40,000 rows in a single custom table and nothing else tells you a great deal very quickly.
Microsoft's documentation on this is at Manage Dataverse auditing if you need the full detail on configuration.
Option 2: Universal Search in XrmToolBox
If auditing was never enabled, or was only enabled recently, the audit log won't have the history you need. In that case the fallback is to go looking at the live data instead.
The tool for this is Universal Search, written by Michael Ochs (Mike Factorial). It searches for a value across every table in Dataverse in one pass, which is exactly the shape of problem we have here.
Step 1: Install the tool
Open XrmToolBox, go to the Tool Library, search for Universal Search and install it. Then connect to the environment you want to investigate.
Step 2: Get the systemuserid of the Application User
This is the bit that makes the search useful. Searching on the display name will give you noisy results, because the name could appear in free text fields, notes, email bodies and all sorts of other places that have nothing to do with the integration.
Instead, get the GUID. The easiest way is to open the Application User record in the user list
https://<<Environment URL>>/main.aspx?pagetype=entitylist&etn=systemuser&forceUCI=1
and pull the id parameter out of the URL.
Alternatively, run a quick query in SQL 4 CDS:
SELECT systemuserid, fullname, applicationid
FROM systemuser
WHERE applicationid IS NOT NULL
That gives you every Application User in the environment along with the Application ID that ties it back to the Entra ID app registration. Worth running regardless, since it's a useful inventory to have.
Step 3: Run the search
Paste the systemuserid GUID into the Universal Search search bar and run it against all tables. Leave Match Case off, since GUID casing can vary in how it is stored and displayed.
You can also narrow the table selection if you have a hypothesis about where to look, but the whole point of the tool is that you don't have to, so I would run it wide the first time.
Step 4: Read the results carefully
Here is the important caveat. Universal Search is a value search, not a column-specific filter. It will return every record across every table where that GUID appears in any searchable field. That means the results will include records where the Application User is:
- the creator (
createdby), which is what you want - the last modifier (
modifiedby) - the owner (
ownerid) - referenced in some other lookup entirely
The tool highlights which field contained the matched value, so you can tell these apart, but you do need to actually look rather than assuming every hit is a Create. In practice this is often useful extra information anyway, since an Application User that owns thousands of records is telling you something about how the integration was configured.
Step 5: Export to Excel
Universal Search has an Open in Excel function which outputs the results across multiple tabs with the matched values highlighted. For an exercise like this, where you are trying to build a picture across many tables at once, that is considerably easier to work with than scrolling the results grid.
Which One to Reach For
The two approaches answer slightly different questions, so it is worth being deliberate about which you use.
Audit Summary View tells you what the Application User did, including operations against records that have since been deleted or reassigned. It is precise about the operation type. It only works if auditing was enabled at the time, and only for tables where auditing was turned on.
Universal Search tells you where the Application User's GUID currently sits in live data. It works with no prerequisites and covers the full history of the environment regardless of when auditing was switched on. But it needs manual interpretation, and it will miss anything the integration created that has since been deleted.
My preference is to run Audit Summary View first if auditing is available, then use Universal Search as a cross check. Where the two disagree, the gap is usually itself informative, since it often points at tables that were excluded from auditing.
What I'd Do Differently
The real lesson from this one is not about the tooling. It is that an Application User with no documented owner is a small piece of technical debt that stays invisible until a secret expires and then becomes urgent.
A few things worth doing while you are already in there:
- Fill in the Description field on the Application User record in Dataverse with what the integration is, who owns it, and where the secret is stored. It is a free text field that nobody uses, and it is exactly the right place for this.
- Record the Application ID against the Entra ID app registration name somewhere your team will actually look.
- Set a calendar reminder well ahead of secret expiry rather than relying on the notification email, which tends to arrive later than you would like.
- Consider moving to certificate based authentication or managed identity where the integration supports it, which sidesteps the secret rotation problem entirely.
Have you had to trace an undocumented Application User before, or found a better way of doing it than these two? I would be interested to hear what worked.

Like
Report



*This post is locked for comments