Skip to content

Identity & Binding

An INK identity names an agent, not a person. A principal identifies the party that holds a private key, and every other claim attached to it is either derived from that key or explicitly unauthenticated. The normative home for this model is ink-identity-model.md; this page is the readable version of it. Why the model is rooted in keys rather than in an external identity system, and what that choice costs, is recorded in decision 0001.

Agent ID

An agent’s wire identifier has the form <method>:<multibase>, where <method> is tulpa or ink and the multibase tail is the base58btc encoding (z prefix) of an Ed25519 public key. Because the key is encoded in the identifier, a receiver can derive a signing key directly from the agentId on the bootstrap path, before any Agent Card has been observed.

A key-derived principal is self-certifying: it identifies exactly the holder of the embedded private key and carries no other claim. There is no directory, no registry and no issuer behind it. Creating one needs nobody’s permission, and nobody can revoke one.

The embedded key is the identity’s genesis key, not its current signing key. It roots the card proof and attests rotations; it does not authorize live messages once a card key set has been observed. See Key rotation for the authority rule and Agent Card for the rooting rules.

Two method prefixes denote the same key-derived identity:

  • tulpa: is canonical. Agents emit tulpa: agentIds, and the canonical examples throughout this spec use it.
  • ink: is an accepted inbound alias carrying the identical multibase tail. It exists so the protocol can move toward a vendor-neutral namespace (see the Naming note) without a breaking rename.

Receivers accept both, emit one: a conforming receiver MUST accept either prefix on inbound messages and SHOULD keep emitting the canonical tulpa: form. Because both spellings carry the same key, a signature made with that key verifies regardless of which prefix carried it; the prefix is identity syntax, not signing authority.

Canonical principal

Since tulpa:zKEY and ink:zKEY are the same actor, a receiver MUST collapse them to a single, prefix-independent principal before making any security decision. All per-sender state (block lists, rate limits, duplicate-payload checks, cached verification keys, replay sets and connection identity) MUST key on that principal, never on the raw agentId string. Otherwise a sender could switch prefix to dodge a block or split a rate-limit window.

Canonicalization does not touch a foreign principal: no case folding, no percent-decoding, no host normalization. did:web:Example.com and did:web:example.com are different principals to INK even though DNS resolves them to the same host, and an implementation MUST NOT fold one onto the other.

Canonical equality answers “is this the same actor I hold state for”. Signed and bound fields are a different question and are compared byte for byte: a fetched card’s agentId against the one requested, the inner and outer from of an encrypted envelope, a directory’s audience against the signed to. Never substitute one comparison for the other.

Foreign principals

Any principal that is not key-derived is a foreign principal, and it is not self-certifying. It identifies whatever the identity system behind it says it identifies, and INK depends on that system for the principal-to-key link.

  • did:web is the one foreign form INK pins a walk for. The host names the discovery base, and the DID document roots the card proof. See Discovery.
  • did:key embeds a key but names no location. It has no discovery surface, so there is no card to fetch and no card proof to root. A resolver MUST report it as unresolvable without making a network request. A deployment MAY still accept a did:key counterparty by decoding the embedded key, but that is a bootstrap key-supply path outside the resolver, the key it yields can never be rotated, and the result MUST NOT be presented as a resolved card.
  • did:plc, did:ion and anything else resolve under the issuing system’s own rules, out of band of INK. A verifier that cannot resolve one MUST reject rather than fall back to a weaker path.

A key-derived principal is permanent and unrecoverable in exactly the way its key material is. A foreign principal may be recoverable, because its root document can name a fresh key out of band.

Trust Hierarchy

Authority flows from key material to the card to the message. Owner identity sits off to the side and never carries any of it.

Diagram

Key Model

An agent’s live keys come from its Agent Card, never from an identifier and never from an external record. INK uses two disjoint roles per agent, and the multicodec enforces the split:

PurposeAlgorithmMulticodecPublished inUsage
SigningEd255190xed01keys.signing on the Agent CardSign outbound messages and bodies, verify inbound ones, sign card proofs and rotation links
Key AgreementX255190xec01keys.encryption on the Agent CardECDH key agreement for payload encryption

Ed25519 and X25519 are related curves but are NOT interchangeable. Implementations MUST maintain separate key pairs, MUST NOT derive one from the other and MUST reject a key whose multicodec does not match the slot it appears in. A key-derived agentId always embeds a signing key; there is no encryption-key-derived principal, and an agent’s encryption key is discoverable only from its card.

Public keys travel as multibase base58btc over the multicodec-prefixed key, and signatures as unpadded base64url. Two keys are the same key when their raw decoded bytes are equal; comparing encoded strings is forbidden.

Lifecycle

Every key entry carries exactly one of active, retired or revoked. Three consequences are identity facts rather than verification details:

  • Rotation does not change the identity. The agentId is frozen at genesis and MUST NOT change when keys rotate.
  • Revocation does not end the identity. It ends a key. A revoked signing key never verifies again, even for artifacts that predate its revokedAt, but the principal continues under its remaining keys.
  • A retired key is the identity’s past. It still verifies stored receipts, audit events and messages within its window, and live transport auth refuses it by default (retired_key_for_live_auth) unless the deployment opts into a bounded grace window.

Recovery is not distinguishable from rotation on the wire, and MUST NOT be expected to be: it is an ordinary rotation-chain link at the next keySetVersion, signed by a prior key or by a pre-declared offline recovery key. Identity loss is observable only as silence. See Key rotation for the full taxonomy.

Owner Linkage (Optional)

An Agent Card MAY carry ownerDid, ownerHandle and atprotoRecordUri, naming the human or organization on whose behalf the agent acts. INK defines no proof that binds an owner to an agent. These are self-asserted strings inside a document the agent itself publishes. A card signature proves the agent’s own key asserted them; it proves nothing about the owner.

Therefore:

  • A verifier MUST NOT treat ownerDid, ownerHandle or atprotoRecordUri as authenticated, signed card or not.
  • A verifier MUST NOT make an authorization decision on ownerDid alone. A deployment that authorizes on owner identity obtains that binding from the identity system that issued the owner DID, out of band of INK, under its own policy.
  • The ownerDid check in the discovery response contract is not an exception. It compares the card’s ownerDid against the DID the resolution went through, so a host that legitimately publishes one DID’s card cannot serve it in answer to another. It is an equality check on a self-asserted field, not owner authentication.

An AT Protocol owner-linkage pipeline

One way a deployment can establish owner linkage out of band is an AT Protocol record. This is a deployment pattern, not an INK artifact: nothing in INK requires it, no conformance category covers it, and an implementation MUST NOT require one of a counterparty.

In that pattern the owner writes a record to their own PDS repo naming the agent and its public keys, and the record’s authenticity comes from the repo commit signature that already authenticates every PDS write. A relying service resolves the owner’s DID, reads the record at the current repo head and checks that it names the agent it is talking to. What that buys is a statement by the owner’s identity system, on the owner’s own authority, that the agent acts for them.

Its limits are worth stating plainly, because they are why INK does not build on it:

  • It inherits the PDS trust boundary. A compromised or malicious PDS can serve a forged record. Mitigations are pinning the observed keys after first contact, cross-checking against the DID document’s authorized signing keys, and alerting on unexpected changes.
  • It is an owner claim, not a signing authority. The keys that make an INK signature valid are the ones on the Agent Card, verified under the card proof and the rotation chain. An owner record that disagrees with the card does not override it.
  • It is one identity system among several. A deployment issuing did:web owners, or none at all, is equally conforming.

Implementations MUST document which owner-linkage posture they operate at, including “none”.

Non-goals

INK deliberately does not provide these. An implementation MUST NOT depend on it to:

  • Identify people. INK identifies agents and defines no proof binding an agent to a human.
  • Guarantee uniqueness beyond key possession. There is no namespace, no registry, no first-come allocation and no dispute procedure. A handle is a display affordance with no uniqueness guarantee and no resolution procedure: a verifier MUST NOT resolve a principal from one, key security state on one or treat two cards bearing the same handle as related.
  • Provide revocation transparency. Revocation is a status in a document the agent publishes, so an agent that withholds a revoking update from one counterparty simply is not seen to have revoked. External observation of card heads through the witness log is the only mechanism that turns this into detectable equivocation, and it is a SHOULD.
  • Link identities. INK defines no way to prove two principals are the same actor and no migration path from one to another. An agent that changes principal is a new agent to every counterparty.