Pre-release. v0.1 is not out yet, so there is nothing to install and no public source to clone — the quickstart builds from a checkout.
Tasks and task grants
A task is one piece of work an agent is doing for one person, against one audience. It is created by the first exchange and it has an expiry of its own, separate from any token.
A task grant is what the agent gets back to keep that task alive. It arrives in the
refresh_token field, because that is the field OAuth clients already know how to use, but it
behaves differently in every way that matters.
Two clocks, not one
Section titled “Two clocks, not one”An agent registration may carry two limits:
{ "max_task_ttl": "PT30M", "max_token_ttl": "PT5M"}max_task_ttl bounds the whole piece of work. max_token_ttl bounds each individual credential
handed out along the way. Both are optional: a registration that names neither is given the
server’s Onbe:Tokens:DefaultTaskTtl (thirty minutes) and DefaultTokenTtl (five minutes), and
every registration is held inside Onbe:Agents:MinTaskTtl…MaxTokenTtl.
This split is the reason long-running work is safe. A job that takes half an hour does not hold a half-hour credential; it holds a five-minute one, renewed as it goes. If that credential leaks — copied out of a log, scraped from a crash dump, read from a process list — the window in which it is worth anything is five minutes, not thirty.
The cap is the task’s remaining life, in both directions. A token is issued for the shorter of
max_token_ttl and whatever is left of the task, so the last token of a 22-minute task is
issued for two minutes, not five. A token never outlives its task; the conformance suite checks
this at issue and at refresh. A task with less than five seconds left is refused a token rather
than handed a dead one.
What a task grant will not do
Section titled “What a task grant will not do”The grant is not a general-purpose credential. It is bound to the task, and the server checks, in order, on every refresh:
- The grant exists.
- The task has not been revoked.
- The task has not expired.
- The task has more than five seconds left — less is
access_deniedwith reasontask_ending, and a client that sees it should stop, not retry. - The sponsor is still active at your identity provider.
- The requested scope is a subset of what the task was already granted.
- The agent’s current registration still allows all of it.
Then it issues a fresh token with the same task_id and a new jti.
So a grant cannot widen scope — a refresh asking for something the task was not granted is
invalid_scope, even when the user and the agent would both allow it. It cannot change
audience: another resource is invalid_target. And it belongs to one agent — the refresh
authenticates the agent exactly as the exchange did, so a grant presented by anybody else does
not exist.
The sponsor check
Section titled “The sponsor check”Step 5 is the one that surprises people. On every refresh the control plane asks your identity provider whether the human is still active, and caches the answer for no longer than the lifetime of the token it is about to issue.
That means a user disabled or deleted at the identity provider has every task fail its next
refresh within one expires_in. Off-boarding somebody stops the agents working on their behalf,
without anybody having to remember that agents existed.
A disabled or deleted user is access_denied. An identity provider that cannot answer is
temporarily_unavailable — never treated as active, because “we could not check” is not the
same as “yes”.
Refresh before you have to
Section titled “Refresh before you have to”Renew at about sixty per cent of expires_in, not when a call comes back 401. By the time you
see a 401 you have already failed a request that mattered.
@onbe/client does this for you and never hands out a token that is about to expire. Doing it
by hand is the single most common source of mid-task failures.
When a task ends
Section titled “When a task ends”Three ways: it expires, it is revoked, or the agent finishes and stops asking. Expiry is handled
by a sweeper that marks the task terminal and revokes its grants, writing one task.expired
record. Expiry is not a revocation, and is never written as one — the distinction matters when
you are reading the ledger back and trying to work out whether something was stopped or simply
finished.
© 2026 Onbe