Security Model
Themesic Agent Tools is built security-first. The guiding rule: all authorization is decided on the server, and the browser is never trusted. Whatever an agent claims, the plugin re-checks the permission for every call.
Access tiers
Every tool declares the tier it requires. The access gate enforces it on each request.
| Tier | Who may call | Typical tools |
|---|---|---|
| Anonymous | Anyone (public, like the WordPress REST API) | Public reads: search, products, categories |
| Session | Any visitor carrying a valid same-session nonce - a guest counts | Cart and checkout, which must work for shoppers who never sign in |
| Authenticated | A real logged-in account | A customer's own orders, memberships, courses, subscriptions |
| Capability | A user whose role holds a specific WordPress capability | Sensitive or custom tools you restrict |
Reads of already-public content are public by design - the same information is on your pages and in WordPress' own REST API. Anything that acts, or that touches a specific user's data, needs more.
A wp_rest nonce issued to a logged-out visitor is bound to the nonce tick, not to an account, and the front-end bridge prints one on every public page so guest carts can work. That makes a nonce a useful same-site and CSRF control, but it is not proof of identity. So a nonce alone can never satisfy the Authenticated tier - otherwise "require login" would mean "scrape the homepage". Tools that read a person's own data check for a real login.
Writes always require a nonce
Every write tool requires a valid same-session WordPress nonce (X-WP-Nonce) in addition to its tier check. This is standard WordPress CSRF protection: a write cannot be triggered by a request that did not originate in the visitor's own session.
The in-page WebMCP bridge supplies the nonce automatically. Over REST, you send it in the X-WP-Nonce header. Server-side agents use an API key instead.
Rate limiting
Two limits protect your site from a runaway or abusive agent:
- Per-caller - how many calls a single identity may make in a window. A tool that declares its own stricter limit (coupon attempts, for example) gets its own counter, so cheap calls cannot drain a sensitive tool's budget.
- Global - caps total tool traffic across the whole site, which resists IP rotation.
Metering runs before the permission decision, on purpose. A rejected call still costs the caller quota, so wrong API keys and unknown tool names cannot be guessed for free.
Requests over the limit are rejected with a rate-limit error and never reach the tool. Both limits are configurable in Themesic Agent Tools > Settings.
Everything denied is logged
The activity log records denials as well as successes - forbidden, rate_limited, invalid_params and tool_unavailable all appear. A product whose whole value is a controlled boundary has to let you see when that boundary is being tested, so an attempt on your site shows up in your own dashboard rather than passing silently.
Per-agent API keys (Pro)
A server-side agent authenticates with the X-Themesic-Agent-Key header instead of a browser session.
- Keys are stored hashed (SHA-256). The database never holds a usable credential, and a key cannot be displayed again after you save it - record it once, at creation.
- Minimum length is 32 characters; shorter entries are rejected with a notice rather than silently dropped.
- The comparison is timing-safe.
- An API key can never reach a capability-gated tool. That is enforced in the identity itself, not by convention.
Confirmation for sensitive actions (Pro)
Any tool you flag in Settings > Require confirmation refuses to run on first call. It returns a single-use token, bound to that caller, that tool and those exact parameters, valid for five minutes. The call proceeds only when the token comes back as _confirm.
Stated honestly: no server-side check can prove a person approved something, because the agent makes the request either way. What this does guarantee is that asking first becomes a protocol the agent must follow rather than a suggestion it can drop, and that one approval can never authorise a different or repeated action. The pending response is success: false with HTTP 202, so a client that checks only the success flag can never record an action that did not happen.