Prompts are not an authorization layer. A system prompt can describe rules, but it cannot prove who the user is, what tenant they belong to, or which data and actions they are allowed to access.
Keep authorization in deterministic application code. Apply normal identity, role, tenant, ownership, and policy checks before data is retrieved, before a tool is called, and before a side effect is committed.
This matters most in RAG and agentic systems. Retrieval should only return documents the caller is allowed to see. Tools should only receive operations the caller is allowed to perform. The model should never be the component that decides whether access is valid.
For retrieval, keep the authority on the server side. The model can provide the search query, but the application should derive tenant, ownership, and permission filters from the authenticated user:
public async Task<IReadOnlyList<DocumentChunk>> SearchAllowedContentAsync(
string modelGeneratedQuery,
ClaimsPrincipal user,
CancellationToken cancellationToken)
{
var tenantId = user.RequireTenantId();
var allowedProjectIds = await permissions.GetAllowedProjectIdsAsync(
user,
cancellationToken);
return await retrieval.SearchAsync(
modelGeneratedQuery,
new RetrievalFilter(tenantId, allowedProjectIds),
cancellationToken);
}
The model controls the query text. It does not control the tenant, caller identity, allowed projects, roles, or authorization decision.
Use prompts to guide behavior and wording. Use authorization code to enforce boundaries. If the model is tricked by direct or indirect prompt injection, the application boundary should still prevent unauthorized data access and unsafe actions.