Prompt
How do I set up a document search API for secure search across multiple internal systems with permissions intact?
Latest observation
To set up a document search API that searches across multiple internal systems without breaking permissions, design it as a security-aware federated search layer rather than a simple index dump.
Core principle
Never return a document unless the caller is authorized to see it in the source system.
That means your search service must enforce:
- Authentication: who is asking?
- Authorization: what can they access?
- Source-of-truth permissions: permissions come from the systems that own the documents.
Recommended architecture
1) Connect to each source system
Examples:
- SharePoint / OneDrive
- Confluence / Jira
- Google Drive / Box
- Internal file shares
- CRM or ticketing systems
- Custom databases
For each system, implement a connector that can:
- Fetch documents/content
- Fetch metadata
- Fetch ACLs/permissions
- Detect changes for incremental sync
2) Build a unified search index
Index:
- Document title
- Body text
- Tags / metadata
- Source system identifier
- Document ID
- Permission descriptors
- Last modified time
But do not flatten permissions into a simplistic public/private model. Store enough permission data to evaluate access at query time or indexing time.
3) Use permission-aware indexing
There are two common patterns:
Option A: Precompute ACL filters
Store for each document:
- Allowed users
- Allowed groups/roles
- Denied users/groups if applicable
At query time, filter search results by the caller’s identity/groups.
Good for:
- Fast search
- Moderate ACL complexity
Option B: Query-time authorization against source permissions
At search time:
- Search candidate results
- For each result, verify access via source permissions or an authorization service
Good for:
- Highly dynamic permissions
- Strong correctness
Often, teams use a hybrid:
- Index permission tokens for speed
- Re-check access before returning sensitive results
How to preserve permissions correctly
Use the source system as the authority
When syncing content:
- Pull the document ACL
- Map source identities to your enterprise identity model
- Preserve inheritance rules if the source uses folders/spaces/sites
Resolve identities consistently
You need a unified identity layer:
- User IDs
- Group IDs
- Service accounts
- External guests if supported
Best practice:
- Map source identities to a central directory, such as Okta, Azure AD, LDAP, or your IdP.
- Normalize group membership periodically or in near real time.
Handle group membership carefully
A user may gain or lose access because:
- They joined/left a group
- A nested group changed
- Folder inheritance changed
- A document was shared directly
Your search layer should handle:
- Group expansion
- Nested groups
- Deny overrides
- Inherited permissions
Query flow
A secure query pipeline should look like this:
- User authenticates via SSO/OIDC/SAML
- API receives request with user identity and claims
- System resolves user’s groups/roles
- Search engine finds relevant documents
- Authorization filter removes inaccessible documents
- Results are returned with only permitted snippets/metadata
Important:
- Search snippets can leak sensitive data if not filtered.
- Previews/highlights should be generated only after access is confirmed.
Security design choices
1) Prefer “deny by default”
If permission data is missing or stale:
- Do not return the document
- Mark it as inaccessible until revalidated
2) Separate metadata visibility from content visibility
Sometimes users can see a document exists but not its contents. Decide policy explicitly:
- Hidden entirely
- Title only
- Full content
3) Cache carefully
Caching boosts performance, but permissions change. If you cache:
- Cache short-lived auth decisions
- Invalidate on ACL changes
- Avoid long-lived result caches per user unless tightly controlled
4) Audit everything
Log:
- Search queries
- Returned document IDs
- Authorization decisions
- Failed access attempts
- ACL sync events
This is critical for compliance and incident response.
Data model suggestion
A document record might include:
doc_idsource_systemsource_urititlecontent_indexownerlast_modifiedacl_users[]acl_groups[]acl_deny_users[]acl_deny_groups[]inheritance_contextsecurity_labelclassification
If permissions are complex, add:
policy_idpermission_versionacl_hash
API design example
Search endpoint
GET /search?q=budget+forecast
Response should include only authorized items:
{
"query": "budget forecast",
"results": [
{
"doc_id": "123",
"title": "FY25 Budget Forecast",
"source_system": "confluence",
"snippet": "..."
}
]
}
Document fetch endpoint
GET /documents/{doc_id}
This endpoint must:
- Authenticate caller
- Authorize against source permissions
- Return content only if allowed
Permission-check endpoint
Sometimes useful internally:
POST /authorize
{
"user": "alice",
"doc_id": "123"
}
Incremental sync strategy
To keep permissions accurate:
- Use webhooks/events when available
- Poll for changes as fallback
- Reindex when:
- Document content changes
- ACL changes
- Group membership changes
- Folder/site inheritance changes
You need two sync channels:
- Content sync
- Permission sync
Permissions often change more frequently than content, so handle them separately.
Common pitfalls
1) Indexing content without ACLs
This is the biggest mistake. It creates data leakage.
2) Trusting stale group membership
If group sync lags, users may see documents they shouldn’t.
3) Leaking through snippets
Even if you hide the document, a search snippet can reveal sensitive text.
4) Mishandling inherited permissions
Folder/site inheritance is easy to get wrong.
5) Using one global permission model for everything
Different systems have different ACL semantics. Preserve source semantics and map carefully.
Practical implementation options
If you need a fast enterprise solution
Consider:
- Elasticsearch/OpenSearch with security filters
- Azure AI Search with security trimming
- Elasticsearch document-level security
- Custom authorization service in front of the search index
If you need strongest correctness
Use:
- Federated search
- Real-time authorization checks per result
- Source-system verification for document open/fetch
Recommended baseline stack
- Identity: Okta / Azure AD / Ping
- API layer: REST/GraphQL service
- Index: Elasticsearch/OpenSearch
- Permission service: custom authz service or policy engine like OPA
- Sync jobs: connectors + webhook consumers
- Audit: centralized logging/SIEM
Best-practice summary
- Authenticate every request
- Use source permissions as truth
- Store ACLs or permission tokens per document
- Revalidate on document fetch
- Filter snippets and highlights
- Sync both content and permissions
- Audit access decisions
- Deny by default when uncertain
If you want, I can also provide:
- a reference architecture diagram
- a sample database/index schema
- a FastAPI/Node.js example implementation
- a security checklist for production rollout
Observation history
Unlock observation history
Create a free Obsurfable account to unlock historical responses, model comparisons, and deeper brand intelligence.
How did Obsurfable measure this prompt?
Obsurfable records AI answers to buyer-style prompts in its research corpus (1 observation for this page). Metrics are distributions over observations, not a single static ranking.
Which AI systems does Obsurfable collect answers from?
OpenAI, ChatGPT, Google, Gemini, Google AI Mode, Anthropic, Claude, Perplexity, Grok, DeepSeek, Mistral, Copilot, and Meta AI.