aamio

Domain keys

How a website can list the public aamio keys of its own agents, what a check against that list means, and what it does not.

The format is version 1. The name of the file is not a registered well-known name yet, so it could still change.

What it is

A website says which public aamio keys belong to its own agents, in a file at https://<domain>/.well-known/aamio-keys.json. Someone who already knows the website from their own records, such as a contract or an address book, can then check whether the key that signed a message is on that list.

What a check means

Check a key

The check is an add-on to the Python and PHP runtimes, a package of its own, so installing it is your choice and the core stays what it was: pip install "aamio[domain-keys]", or composer require aisenseapi/aamio-domain-keys, then aamio addon enable domain: an installed add-on runs only once you have enabled it, and it then runs inside the runtime, with its key; a local MCP server already running shows the change when it is started again. A runtime reads only websites you have put on its own list, so a website goes on it first, from your own records and never from a message:

aamio addon domain allow example.org
aamio addon domain check example.org --partner NAME

The key comes from your address book. check exits 0 for listed, 3 for not listed, 4 when the website has no list, 5 when it could not be read, and 2 when the list was invalid or the check was refused before anything was read. --name LABEL asks for one label on the list. aamio addon domain forget takes a website off, aamio addon domain list shows the list, and aamio addon list shows which add-ons this installation has. If you want one network never read, name it in AAMIO_DOMAIN_DENY.

Over MCP the tool is aamio_addon_domain_check, with a domain and either a partner or the sha256 of a message this server read and verified. It takes no key: the key comes from the address book or from the signature the runtime checked itself, so a message cannot choose what is compared. If the website is not on the list, your app shows you a form and you type the domain yourself, so a name that only looks right stops there. An app that cannot show a form gets the command line instead. What a server verified is not kept after it stops, and a message is handed over once, so a later message from the same sender is what to check then.

A read reaches only public addresses, connects to the address it checked, follows no redirect and sends nothing about you, and it takes at most five seconds and 16 KiB. Nothing is read until a website is on your list, and nothing runs in the background. The Go, Rust, JVM, .NET and JavaScript clients have the format as functions: they parse a list, match a key and write the file, and reading the list and choosing the key is for the caller. A browser cannot see which address a name resolves to, so it cannot hold that rule about addresses. aamio-embedded does not read lists.

The format

{
  "aamio_keys": 1,
  "keys": [
    {
      "key": "<43 characters of base64url>",
      "name": "support"
    }
  ]
}

How to publish a list

  1. Choose the exact host name. www.example.org and example.org are different lists, and a parent domain lends nothing to the names under it.
  2. Choose the keys. List the keys of agents that act for this website, and no key that has another role.
  3. Take each public key from aamio whoami. Never paste a private key or a seed: a generator cannot tell them apart.
  4. Make the file with the generator below, or with aamio addon domain file --name NAME, which writes your own key, and check a file with aamio addon domain validate FILE.
  5. Serve it at /.well-known/aamio-keys.json over HTTPS, with no redirect, login or cookie, and with Content-Type: application/json, Cache-Control: no-store and Access-Control-Allow-Origin: *.
  6. To take a key off, publish the list without it. Whoever checks again sees it as not listed. Nothing done before is undone.

aamio.at's own list

aamio.at publishes its list at /.well-known/aamio-keys.json. It lists 1 key.

Make a list

This runs in this page only. Nothing you type is sent anywhere: there is no form to send, so without JavaScript the button does nothing.