Guides / Agent identity
Agent identity
Without an identity, every agent on a machine is the same agent, and "agent" in the audit log is a word the caller chose for itself. An agent identity is a name, a policy scope and a token that kosa8's service checks on every request.
Why a label is not an identity
When an AI client drives kosa8, each request it sends is marked as coming from an agent. That mark is a claim. Nothing checks it, and nothing in it says which agent. Two things an organisation needs are impossible while that is all there is.
A self-declared label
- The reviewer bot and the release bot get the same tools, because policy has one default scope for "an agent".
- The audit log says an agent did it. It cannot say which.
- An approval given to one agent's call fits another agent making the same call.
A verified identity
- Each agent acts in its own scope, chosen from its record and never by the caller.
- Every audit entry carries the agent's id, name and scope.
- An approval belongs to the agent that asked.
How it works
- A person creates the identity. An agent cannot.
- The token is printed once. kosa8 keeps only a SHA-256 digest of it.
- The agent's gateway is started with the token in its environment.
- The service receives the token with each request, hashes it, and looks for the match.
- A match gives a record: who this is, when it expires, whether it was revoked.
- Tool calls are decided in the scope written in that record.
- The audit entry for the request names the agent, by an id that never changes.
Walkthrough
Mint an identity
$ kosa8 agent token create reviewer --scope eng --ttl 1h agent reviewer (agt_1a2b3c4d5e6f), scope eng, expires 2026-… the token is shown once and is not stored; give it to the agent's gateway as KOSA8_AGENT_TOKEN k8a_…
The two lines of explanation go to standard error and the token goes alone to standard output, so a script can capture it without it passing through a terminal's scrollback.
| Flag | Meaning | Default |
|---|---|---|
--scope | The MCP policy scope the agent acts in. | The policy's default_scope |
--ttl | How long the token works, as a duration such as 8h or 720h. | 24 hours. At most 8760h, which is 365 days. |
A name is 1 to 64 characters from letters, digits, -, _ and
.. Names appear in audit entries and queries, so they are identifiers, not
sentences.
Give it to the agent's gateway
The gateway is the kosa8 mcp serve process your AI client launches. Put the
token in its environment as KOSA8_AGENT_TOKEN. It is read from the environment and
not from a flag so that it never shows up in a process listing.
$ KOSA8_AGENT_TOKEN=k8a_… kosa8 mcp serve kosa8 MCP gateway: AI session … kosa8 MCP gateway: serving agent reviewer (agt_…), scope eng
The gateway asks the service who the token is before it does anything else. If the service does not accept it, the gateway does not start.
See who exists
$ kosa8 agent token ls
ID NAME SCOPE STATE EXPIRES
One row per identity, newest first. STATE is live,
expired or revoked. A scope shown as (default) means the
identity follows the policy's default scope. Tokens are never listed, because kosa8 does not
have them.
Take it away
$ kosa8 agent token revoke reviewer
revoked reviewer
Revoke by name or by id. The record stays, marked as revoked, so old audit entries that name the id still lead somewhere. The service checks the registry on every request, so the next request with that token is refused.
What changes once a gateway is identified
refs.agent: the id, name and scope the service verified. That covers tool
decisions, tool results, sandboxes it creates, and everything else.ask rule is held for
this agent. An approval is bound to its id and cannot be spent by another agent making the same
call. See Rules for tool calls.--http, and no
KOSA8_MCP_TOKEN set, clients authenticate to the gateway with the same agent token
(Authorization: Bearer …). One credential names the agent at both ends, and revoking
it closes both.A different scope for each agent
Here are two agents with different jobs. The reviewer reads. The release bot may merge, and only after a person has approved that exact merge.
- The reviewer's gateway presents the reviewer's token.
- The service finds its record and applies the scope written there.
- That scope lists read tools, so those are the only ones the reviewer is shown.
- The release bot presents a different token and lands in a different scope.
- There, merging is permitted behind an
askrule.
The policy:
{
"name": "example-corp",
"default_scope": "review",
"scopes": [
{ "name": "review",
"description": "read-only agents",
"servers": [
{ "server": "github",
"allow_tools": ["list_*", "get_*", "search_*"] }
] },
{ "name": "release",
"description": "may merge, with a person's approval",
"servers": [
{ "server": "github",
"allow_tools": ["list_*", "get_*", "merge_*"],
"rules": [
{ "id": "merge-needs-a-person",
"tools": ["merge_*"],
"effect": "ask",
"reason": "merging changes what ships" }
] }
] }
]
}
The two identities, minted by a person:
$ kosa8 agent token create reviewer --scope review --ttl 8h $ kosa8 agent token create release-bot --scope release --ttl 8h
Each gateway is started with its own token. Making the least capable scope the default means a gateway with no identity gets the least.
Minting checks that a scope is a well-formed name, not that the policy defines it. An identity
whose scope the policy does not define has every call denied, with a message that lists the
scopes that do exist. kosa8 mcp-policy scopes prints them.
Requiring identity
By default a gateway with no token still works, as the unidentified agent it always was. An organisation can end that with one field in the signed organisation policy:
{
"name": "example-corp",
"require_agent_identity": true
}
Sign and install it as described in Company rules
(kosa8 policy sign, then kosa8 policy install). Under it, two things are
refused.
| What | What it is told |
|---|---|
Starting kosa8 mcp serve with no token | the org policy requires agents to identify themselves: mint a token with `kosa8 agent token create NAME` and start this gateway with KOSA8_AGENT_TOKEN set to it |
| Any request to the service that says it is from an agent and carries no token | HTTP 401: the org policy requires agents to identify themselves, and this request carries no agent token |
Commands you type are not marked as an agent's and are unaffected. If the organisation policy is present and fails verification, the requirement is treated as set: a requirement that cannot be read is not assumed to be absent.
How tokens are kept
| Question | Answer |
|---|---|
| What is stored? | A SHA-256 digest of the token, in ~/.kosa8/agents.json, readable only by you. A copy of that file in a backup or a support bundle is not a set of working credentials. |
| Can I see a token again? | No. It is shown once. A lost token is replaced, not recovered. |
| What does a token look like? | k8a_, the identity's twelve hex digits, and a 256-bit random secret. The id on its own is agt_ and the same twelve digits. |
| How do I rotate one? | Revoke the name, then create it again. One name can have only one live token: creating a second is refused with an agent named "reviewer" already has a live token (agt_…); revoke it first with `kosa8 agent token revoke reviewer`. |
| What happens at expiry? | The token stops working. Create a new one. There is no "never": the longest lifetime is 365 days, and asking for more answers a token may live at most 365 days; rotate longer-lived identities. |
A bad token is refused, not ignored
A request that presents a token which is wrong, expired or revoked is answered with HTTP 401. It is never served as if it had presented no token at all. If it were, revoking an identity would leave behind a working anonymous one, and the revoke would have revoked nothing.
agent token is not recognised; mint one with `kosa8 agent token create NAME` agent reviewer (agt_…) was revoked on 2026-…; mint a new token with `kosa8 agent token create` agent reviewer (agt_…) expired on 2026-…; mint a new token with `kosa8 agent token create`
A gateway started with such a token prints the same sentence after the daemon did not
accept the agent token: and exits. An unknown id and a wrong secret get the same answer on
purpose: saying "that id exists" would be telling the caller half of a credential.
An agent cannot mint identities
An identity carries a scope. An agent that could mint itself a second identity could pick a
wider scope than the one it was given. So a request to create an identity that arrives with an
agent token, or marked as an agent's, is refused with HTTP 403: an agent cannot mint agent
identities.
What the audit log shows
An entry made by an identified agent has the actor agent and a
refs.agent object. An entry with the actor agent and no
refs.agent is now visibly an unverified claim: something said it was an agent and
proved nothing.
Verified
"actor": "agent",
"action": "mcp.decision",
"refs": {
"agent": {
"id": "agt_1a2b3c4d5e6f",
"name": "reviewer",
"scope": "eng"
},
"mcp": { "phase": "call", … }
}
Unverified claim
"actor": "agent",
"action": "mcp.decision",
"refs": {
"mcp": { "phase": "call", … }
}
Refused attempts are recorded as well, as agent.auth.refused with status 401 and
the reason. Read entries with kosa8 audit ls --actor agent, or
kosa8 audit ls --json for the refs. More in
The audit log.
Licensing
Minting an identity needs the Governance subscription, or a trial. Listing and revoking never do: a lapsed subscription must never be the reason an identity could not be taken away.
What this does not do
- Tokens are bearer tokens. Whoever holds the token is that agent. It is not tied to a process, a machine or a sandbox. Keep lifetimes short and revoke what you no longer use.
- There is no single sign-on. Identities are created with a command on each machine and are not connected to a company directory.
- It identifies an agent to the service. It does not stop a process pretending to be you. The service's socket belongs to your user, and anything running as you can call it without a token, as a person would. What changes is that such a call cannot carry an agent's identity, and that an agent entry with no identity is visible as an unverified claim.
- The rule against agents minting identities trusts the same mark. It stops an agent's own gateway. It does not stop a process that lies about being an agent.
- The token is in the gateway's environment. A program that can read that environment can copy it. Run the agent itself in a sandbox, where the gateway's environment is out of reach.
- A revoke stops a running gateway at its next call, not mid-call. The gateway records each decision with the service before it runs the tool; once the service rejects the identity, the gateway refuses the call (
this gateway's agent identity (…) is no longer accepted by the daemon). A tool call that was already running when you revoked finishes. Stop the gateway too if that matters.
Where to go next
Rules for tool calls
What goes inside a scope: tool lists, argument rules and asks.
Tool servers (MCP)
The gateway an identity is given to, and the servers behind it.
The audit log
Reading entries, and proving nobody edited them.
kosa8 agent token create
The command reference, generated from the binary.