Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 48 additions & 12 deletions snippets/collect-browser-credentials.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,22 @@ const item = await kernel.vaults.items.upsert("hn-login", {
type: "credential",
spec: {
description: "Hacker News",
fields: {
username: { type: "text", required: true, sensitive: false },
password: { type: "password", required: true, sensitive: true },
},
fields: [
{
name: "username",
label: "Username",
type: "text",
required: true,
sensitive: false,
},
{
name: "password",
label: "Password",
type: "password",
required: true,
sensitive: true,
},
],
},
});
if (item.type !== "credential") throw new Error("expected a credential item");
Expand All @@ -31,10 +43,22 @@ item = kernel.vaults.items.upsert(
type="credential",
spec={
"description": "Hacker News",
"fields": {
"username": {"type": "text", "required": True, "sensitive": False},
"password": {"type": "password", "required": True, "sensitive": True},
},
"fields": [
{
"name": "username",
"label": "Username",
"type": "text",
"required": True,
"sensitive": False,
},
{
"name": "password",
"label": "Password",
"type": "password",
"required": True,
"sensitive": True,
},
],
},
)
if item.type != "credential":
Expand All @@ -49,10 +73,22 @@ kernel browsers playwright execute "$BROWSER_ID" \
kernel vaults credentials create "$VAULT_NAME" hn-login --spec-file - <<'JSON'
{
"description": "Hacker News",
"fields": {
"username": {"type": "text", "required": true, "sensitive": false},
"password": {"type": "password", "required": true, "sensitive": true}
}
"fields": [
{
"name": "username",
"label": "Username",
"type": "text",
"required": true,
"sensitive": false
},
{
"name": "password",
"label": "Password",
"type": "password",
"required": true,
"sensitive": true
}
]
}
JSON
```
Expand Down
76 changes: 56 additions & 20 deletions vaults/credentials.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,22 @@ const item = await kernel.vaults.items.upsert("portal-login", {
type: "credential",
spec: {
description: "Account Portal",
fields: {
username: { type: "email", required: true, sensitive: false },
password: { type: "password", required: true, sensitive: true },
},
fields: [
{
name: "username",
label: "Email address",
type: "email",
required: true,
sensitive: false,
},
{
name: "password",
label: "Password",
type: "password",
required: true,
sensitive: true,
},
],
},
});
```
Expand All @@ -54,10 +66,22 @@ item = kernel.vaults.items.upsert(
type="credential",
spec={
"description": "Account Portal",
"fields": {
"username": {"type": "email", "required": True, "sensitive": False},
"password": {"type": "password", "required": True, "sensitive": True},
},
"fields": [
{
"name": "username",
"label": "Email address",
"type": "email",
"required": True,
"sensitive": False,
},
{
"name": "password",
"label": "Password",
"type": "password",
"required": True,
"sensitive": True,
},
],
},
)
```
Expand All @@ -68,16 +92,20 @@ use only the recognizable site or service name for `description`. it's the colle

| field setting | behavior |
| --- | --- |
| `name` | required stable machine key for item state, value updates, and browser fill |
| `label` | optional human-readable form text; falls back to `name` when omitted |
| `type` | `text`, `email`, `password`, or `totp` |
| `required` | defaults to `true`; all required fields must have values for the item to become ready |
| `sensitive` | defaults to `true`; leave it `true` for write-only values, or set it `false` only when your backend or collection form needs to read and prefill the value |
| `value` | optional initial value from trusted code; omit it to leave the field unset |

password and totp fields must be sensitive. usernames and email addresses can also remain sensitive; `fill` works either way. fields marked `sensitive: false` return their stored values in item responses.

`fields` is an ordered array. define fields in the same top-to-bottom order as the website; collection forms preserve it exactly. `name` remains authoritative for `state.fields`, updates, and `fill`. `label` only changes display text and is returned as non-secret metadata. labels must be nonempty, trimmed, single-line display text of at most 128 utf-8 bytes.

an item accepts 1–32 named fields. field names must start with an ascii letter, contain only ascii letters, numbers, and underscores, and be at most 64 characters. `email` values must be bare valid addresses such as `user@example.com`; use `text` for usernames that aren't valid email addresses. initial values must be nonempty strings and fit within 16 kib of utf-8 data each; `null` and empty strings aren't accepted on creation.

field names, types, required flags, and sensitivity are immutable. repeating the same creation request retrieves the current item without overwriting later edits. use an update for value changes; use a new item key for a different field definition.
field names, labels, types, required flags, and sensitivity are immutable. repeating the same creation request retrieves the current item without overwriting later edits. use an update for value changes; use a new item key for a different field definition.

### Copy values from an existing vault

Expand Down Expand Up @@ -123,20 +151,24 @@ const item = await kernel.vaults.items.upsert("portal-login", {
type: "credential",
spec: {
description: "Account Portal",
fields: {
username: {
fields: [
{
name: "username",
label: "Email address",
type: "email",
required: true,
sensitive: true,
value: credential.username,
},
password: {
{
name: "password",
label: "Password",
type: "password",
required: true,
sensitive: true,
value: credential.password,
},
},
],
},
});
if (item.type !== "credential" || item.state.status !== "ready") {
Expand All @@ -163,20 +195,24 @@ item = kernel.vaults.items.upsert(
type="credential",
spec={
"description": "Account Portal",
"fields": {
"username": {
"fields": [
{
"name": "username",
"label": "Email address",
"type": "email",
"required": True,
"sensitive": True,
"value": credential["username"],
},
"password": {
{
"name": "password",
"label": "Password",
"type": "password",
"required": True,
"sensitive": True,
"value": credential["password"],
},
},
],
},
)
if item.type != "credential" or item.state.status != "ready":
Expand Down Expand Up @@ -212,11 +248,11 @@ poll the item with a bounded wait until its status is `ready`. readiness means r

invoke the advertised `collect` operation to reopen collection for a ready item. this doesn't clear its values. record its `version` before opening the form, then retrieve without `wait` to observe edits: `wait` waits for readiness, not changes to an already-ready item. a version change can also come from an api update, so it doesn't identify a particular form submission.

the form includes text, email, and password fields, not totp. non-sensitive values can be prefilled; stored secrets aren't revealed. required visible inputs must be populated on submission.
the form includes text, email, and password fields in declaration order, not totp. it renders `label` when present and falls back to `name`. non-sensitive values can be prefilled; stored secrets aren't revealed. required visible inputs must be populated on submission.

## Read and update values

`spec.fields` contains definitions, never initial values. `state.fields` reports `has_value` for each field. it also returns `value` when the field is populated and `sensitive: false`. sensitive values aren't returned.
`spec.fields` contains ordered definitions, including optional labels, but never initial values. `state.fields` remains keyed by stable field `name` and reports `has_value` for each field. it also returns `value` when the field is populated and `sensitive: false`. sensitive values aren't returned.

updates require `type: "credential"` and the latest `version`. send only fields you want to change. bind forms to the immutable item id with `expected_item_id` so a deleted and recreated key can't receive an old form's submission.

Expand Down Expand Up @@ -273,6 +309,6 @@ KERNEL generates a fresh six-digit code immediately before filling, using hmac-s

your authenticated backend can retrieve safe item state and submit value updates using the ordinary item api. authenticate your own users, authorize their access to the vault and immutable item id, and apply the version precondition. keep broad KERNEL api credentials out of the frontend.

render every form-supported field, omit totp, prefill only non-sensitive values, and don't log submitted values. for an unchanged form, use your own completion callback rather than an empty update. KERNEL doesn't store or authenticate your custom collection url.
render every form-supported field in declaration order, display `label` with a `name` fallback, keep controls and updates keyed by `name`, omit totp, prefill only non-sensitive values, and don't log submitted values. for an unchanged form, use your own completion callback rather than an empty update. KERNEL doesn't store or authenticate your custom collection url.

continue with [fill browser fields](/vaults/fill) or the [browser agent cookbook](/browsers/use-vault-credentials-in-browser-agent).
Loading