Authenticate users and enforce AI tool permissions
The short answer
Your application, not the model, decides who a person is and what they may read or change. An email address, an order number or the model’s judgment can’t grant access. Pass trusted identity to tools outside the arguments the model writes, and check that the customer owns the resource on every call.
Match authority to the channel
Three questions are easy to blur together. Who does the person say they are? Has that been proven? And is that proven person allowed to see or change this specific thing? Different channels give you different evidence, and none of them answers all three on its own. The table shows what each kind of evidence establishes and what you still have to check.
| Evidence | What it establishes | What still needs a check |
|---|---|---|
| A name, email or order number in chat | The customer supplied a value | Identity and resource ownership |
| Inbound email | A message arrived through the email channel | Your verification policy, account mapping and action risk |
| Validated application session | The server recognizes a current account session | Resource ownership, roles and allowed action |
| Recent additional verification | The required extra identity step passed | Action limits, resource state and explicit confirmation where required |
Order numbers deserve a special mention. They often appear on packing slips, in forwarded emails and in screenshots, and many follow a predictable pattern. Knowing one is not the same as owning it, so an order number can tell the agent which order a customer means but can never be the reason they get to see it.
Bind the session to the helpdesk conversation
For signed-in chat, use your application’s secure identity route to tell the helpdesk who the customer is. Intercom documents identity tokens that your server issues for the Messenger, along with shutting the session down when the customer logs out. Link conversations to stable account IDs rather than to email addresses, and protect any contact attributes that affect identity so they can’t be edited from the browser. Be careful that a contact record created from an unverified email doesn’t quietly become a trusted user later.
For email and anonymous chat, choose an approved verification route that fits the data or action the customer wants. Checking public delivery guidance needs no verification. Seeing an order’s details might need a sign-in link. Changing an address might need a recent, stronger check. When verification is needed, send the customer to a secure flow in your application. Never ask them to paste a password or a one-time code into a support conversation. Decide how long a verification lasts and what happens when the customer moves from chat to email.
Provider reference: Intercom Messenger identity.
Build a read tool with a narrow contract
The safest tools split their inputs by who is trusted to provide them. In the order-status example, the model can supply order_reference, because the customer told it which order they mean. The application supplies the principal, meaning the verified account making the request, from its own session data. The data access layer then limits the lookup to orders that principal may see. An instruction in the prompt such as “only access this customer’s orders” is not a substitute for that check, because prompts can be ignored or manipulated.
The runnable example returns verification_required when there is no trusted principal. It returns the same not_available result whether the order doesn’t exist or belongs to someone else, so the reply can’t confirm that a guessed order number is real. A successful response contains only the reference, the order state and the estimated delivery date, which is all the agent needs to answer the question.
This is teaching code, not an authentication service. A real implementation also needs input validation against the schema, session expiry checks, rate limits and a protected database query. Its principal must never be built from chat text or from a customer ID the model passes in.
Interpret results without inventing authority
The tool returns a state, and the agent needs clear rules for turning each state into a reply. The supplied example prompt does this. For verification_required, the agent offers the sign-in route your application provides. For not_available, it doesn’t say whether the order exists or who owns it. When the delivery estimate is missing, it says the estimate isn’t available yet instead of guessing a date.
The prompt is new example material, and the Python checks show the access decision and the data shape. They don’t prove that a particular model will always follow the wording rules. Add model test cases that check which tool arguments the model requests and what the final reply says, then add integration tests for logout and account changes during a conversation.
Treat writes as a separate permission
Being allowed to read an order doesn’t mean being allowed to refund it or change its address. Define a policy for each write action. Depending on the action, it may require a particular role, a recent verification, the order to be in a certain state, an amount under a limit, a teammate’s approval and the customer’s explicit confirmation. A refund under a small limit might proceed after confirmation, while an address change on an order that has already shipped goes to a person.
Check those conditions at the moment the action runs. While the agent is working, the customer may sign out, lose a role or change what they’re asking for, so permission granted at the start of the conversation can’t simply be reused. Record which rule allowed the action and what identity evidence it relied on, without copying tokens or other secrets into your logs.
Ask AI to explain this guide
Build decisions and checks
Use these decisions to turn the worked case into your own implementation. A check is complete only when you have evidence for the stated result.
Separate contact details from verified identity
Required. An email typed into chat doesn't prove someone owns the account. An inbound email doesn't automatically authorize a refund.
Build. Define four identity states: anonymous, claimed, authenticated and step-up verified (checked again for a sensitive action). Use trusted server session data for signed-in chat. Choose an email verification route that matches the risk. Record how identity was established. If an identifier is missing or replaced, assess the evidence again. A fallback email doesn't inherit the trust of a validated account session.
Check. A visitor can't get another customer's data by changing an email address or order number.
Authorize each resource and action
When it applies. Login proves who someone is, not that they own every order or can take every action.
Build. Check account membership, resource ownership and the allowed action on the server. Bind trusted customer IDs outside the arguments the model generates. Apply the same checks on every tool path.
Check. Try a valid action on the wrong account. The server refuses it, even when the model asks for it.
Use stronger checks for sensitive actions
When it applies. Even a verified session may not be enough for a high-risk change.
Build. Set risk levels for reads, refunds, cancellations and account changes. Require recent verification, limits, confirmation or human approval where appropriate. Check authority again at the moment of execution.
Check. Test an expired session, a resource that changed and a request above the allowed limit.
Protect identity across time and channels
When it applies. A merged contact, shared mailbox or old conversation can attach the wrong history to a person.
Build. Use stable account IDs, explicit linking rules and expiry. Revalidate identity when the channel changes and for sensitive requests. A fuzzy match on name or email is never permission.
Check. Test logout, contact merges, shared email addresses and returning visitors. Only history the person is authorized to see is available.
Ask AI to apply these decisions
Templates and examples
Every file uses synthetic data. Adapt it to your own policies and test it somewhere safe before it touches customers.
- order_status_example.pyRunnable Python example (synthetic data, no network calls)
- order_status_prompt.txtTemplate (Markdown or text)
- order_status_tool_schema.jsonJSON fixture or schema
order_status_example.py"""Synthetic teaching example. No network calls or real customer data.
This file demonstrates the resource-access decision inside one read-only tool.
It is not an authentication service, webhook handler or complete agent.
Run: python3 order_status_example.py
"""
from dataclasses import dataclass
from typing import Mapping
@dataclass(frozen=True)
class Principal:
# Created only by the application's validated session adapter.
# Never construct this object from a chat message or tool arguments.
customer_id: str
@dataclass(frozen=True)
class Order:
owner_id: str
state: str
estimated_delivery: str | None
def get_order_status(
*,
principal: Principal | None,
order_reference: str,
orders: Mapping[str, Order],
) -> dict:
"""Return only data that this authenticated customer may read."""
if principal is None:
return {"status": "verification_required"}
order = orders.get(order_reference)
if order is None or order.owner_id != principal.customer_id:
# Use the same customer-visible outcome for absent and foreign orders.
return {"status": "not_available"}
return {
"status": "ok",
"order": {
"reference": order_reference,
"state": order.state,
"estimated_delivery": order.estimated_delivery,
},
} Keep it working
Launch is the start of the work, not the end. These are the recurring jobs this part of the agent needs, and who usually owns them.
| Cadence | Owner | Work |
|---|---|---|
| On change | Security | Review new channels and reports of identity failures. |
| Monthly | Engineering | Review role changes and access denials. |
| Monthly | Security | Review abuse, policy exceptions and approval delays. |
| Monthly | Engineering | Audit account-linking errors and the identity data you retain. |
Test your decision
A signed-in customer knows a household member’s order number and postcode. Is that enough to see the order?
Show the expected decision
Only if your application has a defined, verified rule for delegated access, such as a shared household account. Knowing someone else’s details doesn’t create permission. Point the customer to the secure access route or to a person.