Want a live demo of our AI support agents? Join our next webinar on Wed 18 Nov, 9:30am (PT) / 5:30pm (UK)Webinar Wed 18 Nov · 9:30am PT / 5:30pm UK (opens in a new tab)

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.

The support case

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.

EvidenceWhat it establishesWhat still needs a check
A name, email or order number in chatThe customer supplied a valueIdentity and resource ownership
Inbound emailA message arrived through the email channelYour verification policy, account mapping and action risk
Validated application sessionThe server recognizes a current account sessionResource ownership, roles and allowed action
Recent additional verificationThe required extra identity step passedAction 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.

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.

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.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,
        },
    }

All templates and checklists

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.

CadenceOwnerWork
On changeSecurityReview new channels and reports of identity failures.
MonthlyEngineeringReview role changes and access denials.
MonthlySecurityReview abuse, policy exceptions and approval delays.
MonthlyEngineeringAudit 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.

Common questions

Is an Intercom contact a verified application user?

Not automatically. Your integration has to establish and keep a trusted link between the contact and an account in your application. What that account may do through tools is still a separate decision on your server.

Can the model receive a customer ID as an argument?

Keep trusted identity out of the schema the model sees. Your server should supply it from validated context and reject any attempt to replace it.

What can the agent do for a customer who isn’t signed in?

It can answer anything that comes from public knowledge, such as delivery times, return policies and product questions. For account-specific data, it should offer a secure sign-in or verification route, or hand over to a person who can verify the customer.

Sources

Official documentation backs the provider-specific facts; the worked cases and recommendations are teaching material. Check the current API and model version before you build.

Rather skip the build?

My AskAI is an AI support agent that already does all of this inside your helpdesk. Set it up in minutes and pay per AI reply: $0.05 on the Scale plan, with models, hosting and maintenance included.