Attestation
@atiproto/atproto-attestation
Wraps a key pair and produces signature entries for a record's signatures[] array. By default emits inline network.attested.signature entries; with an agent it writes proof records to that agent's PDS and emits strongRefs.
Constructor
new Attestation(options: AttestationOptions)
| Option | Type | Description |
|---|---|---|
| privateKey | string | KeyData | Multibase string (e.g. z…) or a raw KeyData object. Supports p256, k256, p384, ed25519. |
| publicKey? | string | did:key:…. Derived from privateKey when omitted (P-384 must supply this explicitly). |
| role? | string | Default role to embed on every signature (e.g. "appview", "pos", "broker"). |
| issuer? | string | Default issuer DID. Travels with the signature; useful when key does not directly identify the issuer. |
| signatureType? | string | $type of the inline signature record. Default network.attested.signature. |
| proofType? | string | Collection NSID used for proof records when an agent is set. Default network.attested.proof. |
| agent? | AttestationAgent | XRPC-shaped client with did and call(nsid, params, data). When supplied, signatures become strongRefs pointing at proof records the agent writes. |
sign
sign(input: SignInput): Promise<SignatureEntry>interface SignInput {record: RecordMap; // must include a $typerepository: string; // DID that owns the recordfields?: readonly string[]; // record keys to include in the canonical payloadsignatureType?: string; // overrides the constructor defaultmetadata?: SignatureMetadata; // issuer, issuedAt, role, status, ...extras}
Returns an inline InlineAttestation when no agent was configured. When an agent is configured, the proof record is written to its PDS and a RemoteAttestation (a strongRef) is returned instead. The signed CID is identical between the two paths only when the metadata's $type matches. By design, inline and remote attestations are domain-separated.
signAndAppend
signAndAppend<T extends RecordMap>(input: SignInput & { record: T }): Promise<T & { signatures: unknown[] }>
Convenience helper that signs and returns a copy of the record with the new entry merged into signatures[]. If the array already contains an entry by this attestation, that entry is replaced in place rather than appended.
Match rule: inline entries match if entry.key === this.publicKey. Remote entries match if the strongRef's authority DID equals the configured agent's did. Old proof records are intentionally left in the agent's repo so that prior strongRefs continue to resolve.
findOwnIndex
findOwnIndex(args: { signatures: readonly unknown[] }): number
Returns the index of an existing signature on signatures[] that was issued by this attestation, or -1 when none match. Used internally by signAndAppend; exposed for callers who want to inspect or manipulate signatures manually.
Inline example
import { Attestation } from "@atiproto/atproto-attestation";const att = new Attestation({privateKey: "z3u2en7t5LRb4G…",role: "appview",});const entry = await att.sign({record: { $type: "com.atiproto.cart", items: [], currency: "USD", status: "open" },repository: "did:plc:recipient",fields: ["items", "currency", "status"],});// entry = {// $type: "network.attested.signature",// key: "did:key:zDnae…",// cid: "bafyrei…",// signature: Uint8Array(64),// role: "appview",// }
Agent-backed example
Supply any object with a did and a call(nsid, params, data) method (e.g. an @atproto/api Agent or an @atproto/xrpc XrpcClient).
import { Attestation } from "@atiproto/atproto-attestation";import { AtpAgent } from "@atproto/api";const pdsAgent = new AtpAgent({ service: "https://my-pds.example" });await pdsAgent.login({ identifier: "appview.bsky.team", password });const att = new Attestation({privateKey: process.env.APPVIEW_SIGNING_KEY!,role: "appview",issuer: pdsAgent.did,agent: pdsAgent, // writes proof records here});const entry = await att.sign({record: cartRecord,repository: "did:plc:recipient",fields: ["items", "currency", "status"],});// entry = {// $type: "com.atproto.repo.strongRef",// uri: "at://did:plc:appview/network.attested.proof/3lab…",// cid: "bafyrei…",// }