IKRC Content

What Your Search Index Still Answers After You Revoke Access

Retrieval runs against an index, and that index keeps its own copy of who may read what. Connecting the copy back to the system where access is actually granted and revoked is a job somebody has to own.

A project ends on a Tuesday. Somebody removes three people from the document library that held its contracts, which is the correct action in SharePoint. On Wednesday one of those three asks the internal assistant a question and gets back a paragraph from one of those contracts, cited, politely. Nothing errored. No permission was bypassed. The library says one thing and the search index says another, because the index holds a copy of the permissions as they stood the last time something told it to look.

That gap is the subject here. Retrieval runs against an index, and an index is a second store with its own copy of who may read what. Getting the retrieval layer right comes first; keeping its permission copy honest is the part that gets discovered late, usually by the person who assumed revoking access in the source system was the end of it.

What the Index Knows About Who Can Read

The copy is literal. In Azure AI Search the permissions land as ordinary fields on each document: a user field and a group field, both Collection(Edm.String), both filterable, and both left non-retrievable so the identifiers never come back in a result. An ADLS Gen2 source adds a third field for the container role scope. The index carries permissionFilterOption enabled, which is the switch that makes the service consult any of it.

At query time the caller brings a Microsoft Entra token in the x-ms-query-source-authorization header. The service pulls the user, group and scope claims out of that token, compares them against the permission metadata already stored in the index, and returns only the documents whose stored metadata grants that caller access. Two gates sit in that sentence: the application needs Search Index Data Reader to reach the index at all, and then the token decides which of its documents come back.

The middle clause carries the whole problem. That comparison is fast enough to sit inside a chat response precisely because nothing in the query path calls SharePoint or the storage account to ask what the permissions are today, and what it reads instead is whatever was written into the index the last time the indexer looked.

Permission Refresh Is Not Content Refresh

The ADLS Gen2 reference states the boundary about as plainly as documentation ever does. Enabling access control enrichment on an indexer works automatically in two situations and no others: the very first full indexer run, when every permission that exists at that moment is captured, and brand-new documents added after the feature was switched on. Everything else is a decision somebody has to make and then keep making.

Change a permission on a document already in the index and the same page says what happens: the change does not appear in the search index unless you tell the indexer to crawl the permission metadata again. Three mechanisms do that, sized to the change. Touching the Last-Modified timestamp on a blob refreshes that one document on the next run. Calling resetdocs with a list of document keys covers dozens to thousands. Calling resync with the permissions option covers the whole data source, and its asymmetry matters: it refreshes the access metadata and leaves the content untouched, which is what makes it cheap enough to run on a schedule.

The warning under that table is worth repeating, because teams do not believe it until they watch it. If you change permissions on indexed documents and do not trigger one of those mechanisms, the search index continues serving outdated ACL or RBAC data. No error. No log line. Correct-looking answers, drawn from documents the caller lost access to at some earlier point nobody recorded.

SharePoint has moved, and the move is the reason to check which API version your indexer actually calls. From the 2026-05-01-preview REST API, access control changes on items with unique permissions are detected and refreshed on every successful indexer run, using SharePoint change tokens the same way content changes are picked up. That closes the case people demonstrate: revoke one person on one file, run the indexer, watch the document leave their results.

It does not close the case people perform. Changes inherited from a parent scope - site, library, list, or folder - are not picked up automatically, and the documentation gives that its own table row with resync named as the remedy. Removing somebody from a library is a parent-scope change. So is tightening a folder. So is the end-of-project cleanup three paragraphs up, which is why that opening was not a hypothetical.

One thing to confirm rather than assume: the security guidance page for the service still describes SharePoint access control lists as captured on first indexing, while the SharePoint how-to page dated two days later describes the incremental behaviour above. Which one holds for you depends on the API version your indexer calls.

What all of it adds up to is a job. A named job that refreshes permission metadata on its own cadence, with a recorded last-success time a support person can read without opening the Azure portal. If the answer to when permissions last resynced is a shrug, the index is serving whatever it captured, and nobody knows what that was.

Which Enforcement Fits What You Already Run?

Four approaches exist and one of them is finished. Native POSIX-like access control lists and role scopes, Microsoft Purview sensitivity labels, and SharePoint access control lists are all preview on the 2026-05-01-preview REST API. Security filters are the fourth, and the overview page describes them as API-agnostic, generally available, and based on simple string matching. For a business that has to support what it ships next quarter, that sentence is most of the comparison.

A security filter is exactly what its name says and no more. You store a group or user identifier as a string on the document, and at query time you pass the caller identity into an OData filter that drops anything failing to match. The reference is blunt about the limit: there is no authentication or authorization through the security principal, which is just a string used in a filter expression. That makes the filter a retrieval rule rather than a permission check, and any code path that forgets to attach it returns everything the index holds.

If you build one, build it with search.in from the first commit. A disjunction of equality expressions is fine in a demo, and the reference is specific about where it stops being fine: in cases where the list contains hundreds or thousands of values, it slows down query response time by many seconds. Use search.in instead of an equality expression and you can expect subsecond response times. A user in forty groups is ordinary in a company of two hundred people, which makes this a day-one sizing decision.

Native ingestion earns its preview API when the content already sits in ADLS Gen2 or SharePoint and the identities are already Microsoft Entra. Filters earn theirs when the identities live in your own database, in a customer portal or an operations system with its own roles, because there is no Entra group to ingest and inventing one is a larger project than the search feature that prompted it.

What Can Anybody Prove Three Months Later?

Two documented gaps fail closed, which is the right direction and still generates the ticket. The first is chunking. If a skillset splits documents for vectorization, every chunk must carry the ACL fields, because permission filters apply per document and a chunk is a document. When that skillset runs with projectionMode set to skipIndexingParentDocuments, the indexer field mappings for those fields are bypassed entirely and the values have to be projected onto each chunk. Miss it and the fields land empty, and an empty permission field matches nobody.

The second is group nesting. A Microsoft Entra group nested inside a SharePoint site group does not expand during resolution, and the documentation states that results depending on that relationship are filtered out. Both failures reach support in the same words: the assistant cannot find a document the person can open in their browser. Neither leaks anything. Neither shows up in the answer text.

Diagnosis is cheap when it was built in. Set retrievable to true on the user and group fields, run an elevated read query, confirm the collections are populated on every chunk, then set retrievable back to false. Diagnostic logging into Azure Monitor turns one complaint into a pattern, and it cannot be added after the question is asked, because the queries being asked about have already run.

The record support actually needs is short, and almost nobody keeps it: which index answered, which API version the indexer runs on, when permission metadata last resynced successfully, and whether the document in question carried access fields at all. No single console shows those four together, so they belong on one runbook page that somebody keeps current.

Where IKRC Fits

The part that gets skipped is rarely the search configuration. It is the join between the system where access is granted and revoked and the job that copies those decisions into the index: who performs a revoke, at which scope, what triggers the refresh, how wide the window is, and what somebody sees when it fails. That is integration work sitting on top of a search product, and IKRC does it through software and system integration on estates that already run a document store, an identity directory and a line-of-business application that all disagree slightly.

A useful first conversation needs three things: the list of sources the index pulls from, the name of the person or process that removes access, and whether anyone can currently say when permission metadata was last refreshed. Call IKRC at 646-783-1441 or email info@ikrc.co.

Related Reading

For the retrieval layer underneath all of this, read Before You Add AI, Fix the Data Retrieval Layer. For what changes when the embedding step moves into the database itself, read SQL Server 2025 as an AI platform.

Need this solved in your software?

IKRC builds the custom systems, integrations, and modernization work discussed in this article.

Ready to Build?

Let's engineer your solution.

Every project starts with a conversation. Tell us what you're trying to solve.