Skip to content
Uno Docs

KeyService

KeyService manages the signing keys of the caller's namespace, and publishes the key history of any namespace.

An owner holds a keyring of Ed25519 keys. At most 10 keys are active at once. At most 1 active key is custodial, and the server holds it. Any other key is self-owned: the owner holds it and signs with it. While custodial signing is on, at most 9 keys are self-owned, so the custodial key always has a place.

Conventions and error codes: see common.proto.

A key-change credential that is missing, invalid, ended or refused by uno-api answers permission_denied, never unauthenticated. A client that refreshes its session on unauthenticated would revoke the credential that it holds. A credential that the server already used answers failed_precondition: call ListKeys to see whether the change happened.

Who may change keys:

  • A guest that has never been claimed gives its control proof, as for every RPC. The control proof is the owner authorization.
  • An account gives a key-change credential in key_change_token. The credential comes from KitCredentialService.IssueKeyChangeCredential, after a fresh passkey step-up for this exact change. It lives at most 120 seconds, and the server consumes it once.
  • The control key of a guest that an account has claimed cannot change keys. An OAuth bearer or a delegation never changes keys.

GetKeyHistory is the one RPC here that needs no credential. See its comment.

A rotation, removal, revocation, or custody off raises the authority generation. The key leaves the active set at once. A write with a lease at the old generation may still land until the server completes the generation call. ListKeys shows the key as retiring or revoking until then.

These RPCs take no idempotency_key. Each change needs a fresh proof that the server consumes once. After an uncertain answer, call ListKeys.

CreateKeyChallenge

POST/rpc/uno.kit.v1.KeyService/CreateKeyChallenge

Issues a challenge for the proof of possession of EnrollKey. The challenge is single use and lives 120 seconds.

Header Parameters

Connect-Protocol-Version
number·const 1

Define the version of the Connect protocol

Example1
Connect-Timeout-Ms
number

Define the timeout, in ms

Example1000

Request Body

application/json

Responses

EnrollKey

POST/rpc/uno.kit.v1.KeyService/EnrollKey

Adds a self-owned key. The new key signs a statement to prove that the caller holds it. See EnrollKeyRequest.signature.

Header Parameters

Connect-Protocol-Version
number·const 1

Define the version of the Connect protocol

Example1
Connect-Timeout-Ms
number

Define the timeout, in ms

Example1000

Request Body

application/json
publicKey
string

The Ed25519 public key to add: 64 lowercase hex characters. An owner holds a public key active once. A public key that was removed (retired) may enroll again as a new key. A revoked public key never returns.

challenge
string

The challenge of CreateKeyChallenge.

expiresAt
string <int64>

The expires_at of the challenge, as the response gave it.

signature
string

The Ed25519 signature of the new key, 128 lowercase hex characters, over these lines joined with "\n", with no final newline: uno-kit-key-possession-v1 <deployment origin, for example https://kit.uno.fun> uno.kit.v1 <public_key> <expires_at as decimal digits> The statement is distinct from the guest control proof, so one key may serve both purposes.

keyChangeToken
string

An account caller gives the credential for "enroll" and public_key. A guest leaves it empty.

Responses

Reads the public key history of a namespace: every key, and every change to its status, in the order that the server made them. Anyone may call it, with no credential. It is the evidence behind a verify answer: ownership of a namespace is Uno-attested, and this history is how a third party checks which keys the keyring held and when.

POST/rpc/uno.kit.v1.KeyService/GetKeyHistory

The history holds only the key id, the public key, the kind and the times. It names no account, no owner, no custody setting and no device.

It is append-only. The server adds events and never changes or removes one, so a page that a client read stays true. history_version moves only forward.

How to read it. Order events by seq. Never order them by at: the at of a *_EFFECTIVE event is a bound, and it can be later than the at of an event with a higher seq. The status of a key is the last of its events:

  • CREATED: active.
  • RETIRED, with no RETIREMENT_EFFECTIVE after it: retiring. A write that held a lease at the old authority generation may still land.
  • RETIREMENT_EFFECTIVE: retired. No write that the key signed lands from the at of that event.
  • REVOKED, with no REVOCATION_EFFECTIVE after it: revoking.
  • REVOCATION_EFFECTIVE: revoked. A signature that landed at or after revoked_from reports retroactive revocation. Raw validity stays intact. A key that was retired and then revoked has both pairs of events.

A namespace that no owner holds, and one with no key yet, answer the same: no events and history_version 0. A visitor cannot tell them apart. namespace must be an owner UUIDv7: lowercase, with dashes, no prefix. Any other value fails with invalid_argument.

The call costs a visitor the heavy bucket of the anonymous read limit.

Header Parameters

Connect-Protocol-Version
number·const 1

Define the version of the Connect protocol

Example1
Connect-Timeout-Ms
number

Define the timeout, in ms

Example1000

Request Body

application/json
namespace
string

The owner UUIDv7 that names the keyring.

pageSize
integer <int32>

At most 100. The default is 50.

pageToken
string

The next_page_token of the last page, unchanged. Empty reads the first page.

Responses

ListKeys

POST/rpc/uno.kit.v1.KeyService/ListKeys

Lists every key of the caller's namespace, active or not, in the order that the server made them.

Header Parameters

Connect-Protocol-Version
number·const 1

Define the version of the Connect protocol

Example1
Connect-Timeout-Ms
number

Define the timeout, in ms

Example1000

Request Body

application/json
pageSize
integer <int32>
pageToken
string

Responses

RemoveKey

POST/rpc/uno.kit.v1.KeyService/RemoveKey

Retires a self-owned key. The key signs no more, and its history stays valid. The key id never returns. The same public key may enroll again, as a new key with a new key id.

Header Parameters

Connect-Protocol-Version
number·const 1

Define the version of the Connect protocol

Example1
Connect-Timeout-Ms
number

Define the timeout, in ms

Example1000

Request Body

application/json
keyId
string

The key id of a self-owned key. Use RotateCustodialKey to replace the custodial key.

keyChangeToken
string

An account caller gives the credential for "remove" and key_id. A guest leaves it empty.

Responses

RevokeKey

POST/rpc/uno.kit.v1.KeyService/RevokeKey

Revokes an active or retired key. Landings at or after the requested time report retroactive revocation. Raw signature validity stays intact. Custody off refuses the last active self-owned key. With custody on, the next write replaces a revoked custodial key.

Header Parameters

Connect-Protocol-Version
number·const 1

Define the version of the Connect protocol

Example1
Connect-Timeout-Ms
number

Define the timeout, in ms

Example1000

Request Body

application/json
keyId
string
effectiveFrom
string | null

Unix seconds, from the epoch through now. Absent means now. Zero means the epoch.

keyChangeToken
string

Account credential for revoke, this namespace, and "<key_id>:<effective_from or now>". The time uses canonical decimal digits. A guest sends no credential.

Responses

RotateCustodialKey

POST/rpc/uno.kit.v1.KeyService/RotateCustodialKey

Replaces the active custodial key and retires the old key. History stays valid. The request must name the current key. Call ListKeys after an uncertain answer.

Header Parameters

Connect-Protocol-Version
number·const 1

Define the version of the Connect protocol

Example1
Connect-Timeout-Ms
number

Define the timeout, in ms

Example1000

Request Body

application/json
keyId
string

The current active custodial key id: "key:" and a UUIDv7.

keyChangeToken
string

An account gives the credential for "rotate" and key_id. A guest leaves it empty.

Responses

SetCustody

POST/rpc/uno.kit.v1.KeyService/SetCustody

Turns custodial signing on or off. Off retires the custodial key and makes no new one. Off needs an active self-owned key. On needs room for the custodial key: at most 9 active self-owned keys.

Header Parameters

Connect-Protocol-Version
number·const 1

Define the version of the Connect protocol

Example1
Connect-Timeout-Ms
number

Define the timeout, in ms

Example1000

Request Body

application/json
custodyEnabled
boolean

True turns custodial signing on. False turns it off, and needs an active self-owned key.

keyChangeToken
string

An account caller gives the credential for "set_custody" and "on" or "off". A guest leaves it empty.

Responses