Tutorial: quickstart¶
Goal¶
At the end you will store a secret, issue a wrapped token, and watch an agent list the credential and call an API with it, without the value ever coming back.
Every command and output below comes from a real run, recorded in demo/tutorials/quickstart/expected/ and checked by run.sh --check.
Run it¶
bash demo/tutorials/quickstart/run.sh all
bash demo/tutorials/quickstart/run.sh --check
Script: demo/tutorials/quickstart/run.sh.
1. The human stores a secret and a policy¶
Outside the chat, as the vault administrator. API_URL is stored too: any value can be a reference, not only passwords.
# The human stores a secret and a read policy (outside the chat)
$ bao kv put -mount=secret my-project/dev API_TOKEN=tok-fake-not-a-real-secret API_URL=http://127.0.0.1:18080/health
======= Secret Path =======
secret/data/my-project/dev
======= Metadata =======
Key Value
--- -----
created_time <time>
custom_metadata <nil>
deletion_time n/a
destroyed false
version 1
exit_code=0
$ bao policy write my-project-read deploy/policy-project-read.hcl
Success! Uploaded policy: my-project-read
exit_code=0
2. The agent sees the tools, the session and the names¶
Each khcall is one MCP session, and each session uses a fresh wrapped token. keyholder_status reports the TTL and policies but never the token; keyholder_list returns names only.
# The agent sees the tools, the session and the reference names
$ BAO_WRAPPING_TOKEN=<wrapped token> khcall -tools
keyholder_list
keyholder_run
keyholder_status
exit_code=0
$ BAO_WRAPPING_TOKEN=<wrapped token> khcall keyholder_status keyholder_list
### keyholder_status
{
"addr": "http://127.0.0.1:18200",
"initialized": true,
"kv_mount": "secret",
"scope": "my-project",
"sealed": false,
"server_version": "2.7.1",
"token_expire_time": "<time>",
"token_policies": [
"default",
"my-project-read"
],
"token_renewable": true,
"token_ttl_seconds": <ttl>
}
### keyholder_list
{
"entries": [
{
"ref": "vault://my-project/dev/API_TOKEN",
"version": 1
},
{
"ref": "vault://my-project/dev/API_URL",
"version": 1
}
],
"note": "Use {{vault://path/KEY}} in the args, env or files of keyholder_run.",
"scope": "my-project"
}
exit_code=0
3. The agent calls an API with the token¶
The test API answers with the header it received. The agent reads [hidden:...]; the last line confirms, by hash, that the API received the real stored value. The audit line on stderr names the command and the references, never the value.
# The agent calls an API with the token; the value is masked
$ BAO_WRAPPING_TOKEN=<wrapped token> khcall keyholder_run '{"command":"curl","args":["-sS","-H","Authorization: Bearer {{vault://my-project/dev/API_TOKEN}}","{{vault://my-project/dev/API_URL}}"]}'
{
"exit_code": 0,
"refs_used": [
"vault://my-project/dev/API_TOKEN",
"vault://my-project/dev/API_URL"
],
"stderr": "",
"stdout": "api says: hello, caller with header Authorization: Bearer [hidden:vault://my-project/dev/API_TOKEN]\n"
}
--- stderr
<timestamp> audit cmd="curl" refs=[vault://my-project/dev/API_TOKEN vault://my-project/dev/API_URL] exit=0 dur=<duration> status=ok
exit_code=0
Did the API receive the stored token? yes