Quickstart

Load a credential, present it with selective disclosure and holder binding, verify both signatures, and complete a handshake -- all locally.

Prerequisites

pip install agentmarque

Step 1: Load a credential

Your agent receives a signed credential from the AgentMarque registry. Load it from storage:

from agentmarque import AgentCredential

credential = AgentCredential.from_json(stored_credential_json)

print(credential.did)         # "did:key:z6MkAgent..."
print(credential.issuer_did)  # "did:web:api.agentmarque.com"

The credential contains your agent's identity, capabilities, trust metadata, and a cnf claim that binds it to your agent's public key.

Step 2: Present with holder binding

Create a presentation that reveals only the fields the verifier needs. Your agent's private key signs a Key Binding JWT (KB-JWT) that proves you control the subject key.

presentation = credential.present(
    holder_key=my_private_key,
    verifier_nonce="nonce-from-hotel",
    audience="did:web:hotel-api.com",
    disclose=["verificationTier", "reputationScore", "organization"],
)

The result is a compact string: <issuer-signed-sd-jwt>~<disclosures>~<holder-signed-kb-jwt>. The KB-JWT includes the nonce, audience, and a hash of the disclosed SD-JWT, preventing replay and impersonation.

Step 3: Verify

Create a verifier and check both signatures, holder binding, nonce, audience, and policy.

from agentmarque import AgentMarqueVerifier

verifier = AgentMarqueVerifier(
    trusted_issuers=["did:web:api.agentmarque.com"]
)
result = verifier.verify(
    presentation=presentation,
    expected_nonce="nonce-from-hotel",
    expected_audience="did:web:hotel-api.com",
    min_tier=2,
    min_reputation=60.0,
)

assert result.valid
assert result.checks.signature      # issuer signed the credential
assert result.checks.holder_bound   # agent signed the KB-JWT
assert result.checks.nonce          # nonce matches
assert result.checks.audience       # audience matches

The verifier checks in order: issuer signature, holder binding, cnf match, nonce, audience, expiry, revocation (fail closed), and policy.

Step 4: Handshake

The handshake is a structured challenge-response wrapping the same holder-bound presentation flow.

from agentmarque import AgentHandshake

# Verifier creates a challenge
challenge = AgentHandshake.create_challenge(
    audience="did:web:hotel-api.com",
    ttl=300,  # 5 minutes
)

# Agent responds with a holder-bound presentation
response = AgentHandshake.respond(
    challenge=challenge,
    credential=credential,
    holder_key=my_private_key,
    disclose=["verificationTier", "reputationScore"],
)

# Verifier checks everything
result = AgentHandshake.verify_response(
    response=response,
    expected_challenge=challenge,
    verifier=verifier,
    min_tier=2,
)

assert result.valid

The handshake delegates to the same AgentMarqueVerifier for all checks. The challenge includes a TTL so expired challenges are rejected automatically.

Self-hosting and testing

For local development or running your own registry, use the issuer module:

from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from agentmarque.issuer import issue_credential
from agentmarque.crypto import public_key_to_did_key

# Separate issuer and agent keys
issuer_key = Ed25519PrivateKey.generate()
agent_key = Ed25519PrivateKey.generate()

credential = issue_credential(
    issuer_key=issuer_key,
    subject_did=public_key_to_did_key(agent_key.public_key()),
    subject_key=agent_key.public_key(),
    agent_name="translate-agent",
    organization={"id": "https://acme.co", "name": "Acme Corp"},
    capabilities=["translate"],
    verification_tier=2,
    reputation_score=87.5,
)

# Now present as usual
presentation = credential.present(
    holder_key=agent_key,
    verifier_nonce="test-nonce",
    audience="did:web:localhost",
)

What's next?

Was this page helpful?