The boundary
Where authorization actually happens, and the four things that are frequently mistaken for it.
The gateway is the authorization boundary. Everything else is convenience, presentation or hint.
The test of whether something is a security boundary is simple: what happens when you remove it? Apply that test to each layer.
#The LLM is not the boundary
An agent's reasoning decides what to attempt. It does not decide what is permitted.
Remove the model's good judgement — through prompt injection, a jailbreak, a bad fine-tune, or simply a confident mistake — and nothing about what the agent may do changes. The gateway still runs twelve stages against the same authority and the same policy.
Do not put authorization in a system prompt
"You are only allowed to refund up to ₹1,000" is an instruction, and instructions are negotiable. Anything that can be reasoned with can be reasoned out of.
The ceiling belongs in a delegation and a policy rule, where it is a number the agent cannot see and cannot argue with.
#The SDK is not the boundary
The SDK formats requests, signs assertions, and gives you typed errors. It cannot grant authority and it does not cache a permission.
Remove it and the agent has no credential to call your tool with, because the credential lives in the broker and is released only after an action is permitted. An agent that bypasses the SDK finds it has nothing to call with.
That is why the SDK can be genuinely non-load-bearing rather than merely described as such. The security property does not come from the SDK being present; it comes from the secret being absent.
If your agent currently holds a long-lived API key, this does not hold
The SDK is only non-load-bearing because the agent has no credential. An agent with a key in its environment can call your API directly, and no amount of SDK discipline changes that.
Moving that key into the broker is the single highest-value change you can make. → Broker a credential
#The browser is not the boundary
The console hides navigation items you cannot use, so you are not led to a screen that will refuse you. That is a courtesy.
ts// From the console's navigation model:
// `permissions` gates *rendering only*. A nav item the operator cannot use is
// hidden so they are not led to a screen that will refuse them; the control
// plane re-authorizes every request regardless.
Remove the console entirely and nothing about who can do what changes. Every request is re-authorized server-side against the session's actual permissions.
Never reason about security from what the UI displays.
#The handshake is not the boundary
The handshake tells an agent what the server currently thinks it may call. It is useful for failing fast and for logging.
tsconst info = await agent.handshake();
console.log(info.authorizedTools);
It is not a permission grant and nothing in it is trusted on the next call. Every action re-runs the full pipeline. Do not implement "the handshake said I could, so skip the check" — there is no check to skip.
Same reasoning applies to the Agent Passport. It is a signed snapshot, and the gateway does not authorize from it. If it did, revoking an agent would not take effect until its passport expired, which could be thirty days. → Agent Passport
#What the boundary actually is
textagent process gateway process your downstream
───────────── ─────────────── ───────────────
reasoning ──signed──▶ 1 REQUEST
SDK assertion 2 AUTHENTICATION
(no credential) 3 IDENTITY
4 LIFECYCLE
5 CAPABILITY
6 DELEGATION
7 POLICY
8 RISK
9 APPROVAL
10 CREDENTIAL ──leased──▶
11 EXECUTION ──────▶ real call
12 RESULT
Three properties make it a boundary rather than a layer:
A different process. The agent cannot modify, skip or short-circuit it. In a real deployment it is a different host, reached over the network, behind its own ingress.
Every call, every time. No cache, no fast path, no session-scoped grant.
The secret is on the far side. Stage 10 is the first stage with a side effect outside Veefore, and everything that can refuse has already refused.
#The ordering is part of the guarantee
Brokering last is what makes BLOCK mean blocked.
If the credential were issued earlier — for latency, say — then a blocked action would already have caused a credential to be issued. "We blocked it" and "the secret did not go out" would become two different claims, with only one of them true.
#Deployment topology matters
text ingress: console + control plane ingress: gateway
/v1/* only /gateway/v1/* only
│ │
people, CLI, CI agents
Do not expose `/v1/*` where agents can reach it
The control plane is where policies are activated, credentials are registered and delegations are created. It has no business being reachable from wherever your agents run.
Separate ingresses. The gateway exposes only /gateway/v1/* and
/.well-known/veefore-platform-key. → Deployment
#In one sentence
An agent is a principal that can ask. The gateway is the only thing that can answer. Everything between them is convenience, and removing any of it changes what is convenient, not what is permitted.