Private tools
What a tool sees
| Placeholder | Value |
|---|---|
$auth.subject | The token's sub |
$auth.token | The raw JWT, to forward to your API |
$auth.claims.<name> | Any custom claim |
yaml
# tools/my_bookings.yml
description: The visitor's upcoming bookings.
when_to_use: When they ask about their own bookings.
access: private
request:
method: GET
base_url: $env.API_URL
path: /api/bookings
headers:
Authorization: Bearer $auth.token
respond:
data:
bookings: bookingsYour endpoint verifies the same JWT with the same public key, and scopes the query to its sub.
Rules
Never take the user's id as a parameter. The model fills parameters, and it can be talked into filling that one with someone else's id. A private tool declaring user_id, customer_id, account_id, member_id, patient_id or subject fails the deploy:
text
tool my_bookings: a private tool cannot take "user_id" as a parameter — the model
fills parameters and can be talked into filling that one with someone else's id.
Use $auth.subject, which comes from the verified tokenDerive the user from the token instead. An endpoint that accepts an id has to remember to scope it every time, forever; one that reads the token cannot forget.
Other errors you may hit:
| Error | Fix |
|---|---|
access: private needs an auth: block | Add auth: with public_key: |
auth.public_key ... is a PRIVATE key | Point at identity.pub, not identity.pem |
auth.algorithm must be one of RS256... | Sign with RS256/ES256, not HS256 — a shared secret cannot live in a manifest |
auth.mint.url must be https:// | Use https:// or an $env. placeholder |
access must be "public" or "private" | Scheme names are gone; use private |
auth/ holds JavaScript auth providers, which are gone | Delete auth/, sign a JWT instead |
JavaScript tools are gone | Delete tools/*.js and lib/*.js; describe the call in tools/<key>.yml |
A rejected token — wrong key, expired, wrong aud — leaves the visitor anonymous rather than erroring, and the agent falls back to its public tools. vatio chat shows the reason.
