agentpin
Domain-anchored cryptographic identity for AI agents. Part of the ThirdKey trust stack (SchemaPin → AgentPin → Symbiont).
Requires Python >= 3.8.
Install
pip install agentpin
Quick Start
from agentpin import (
generate_key_pair,
generate_key_id,
pem_to_jwk,
issue_credential,
verify_credential_offline,
build_discovery_document,
KeyPinStore,
Capability,
)
# Generate keys
private_key_pem, public_key_pem = generate_key_pair()
kid = generate_key_id(public_key_pem)
jwk = pem_to_jwk(public_key_pem, kid)
# Build discovery document
discovery = build_discovery_document(
"example.com", "maker", [jwk],
[{
"agent_id": "urn:agentpin:example.com:my-agent",
"name": "My Agent",
"capabilities": ["read:data", "write:reports"],
"status": "active",
}],
2,
)
# Issue credential
credential = issue_credential(
private_key_pem=private_key_pem,
kid=kid,
issuer="example.com",
agent_id="urn:agentpin:example.com:my-agent",
audience="verifier.com",
capabilities=[
Capability.create("read", "data"),
Capability.create("write", "reports"),
],
constraints=None,
delegation_chain=None,
ttl_secs=3600,
)
# Verify credential
result = verify_credential_offline(
credential_jwt=credential,
discovery=discovery,
revocation=None,
pin_store=KeyPinStore(),
audience="verifier.com",
)
if result.valid:
print(f"Agent: {result.agent_id}")
print(f"Capabilities: {result.capabilities}")
print(f"Key pinning: {result.key_pinning}")
else:
print(f"Failed: {result.error_code} - {result.error_message}")
Features
- ES256 (ECDSA P-256) cryptographic credentials
- Domain-anchored
.well-known/agent-identity.jsondiscovery - 12-step verification protocol
- Maker-deployer delegation chains
- Capability-scoped credentials with constraints
- TOFU key pinning (compatible with SchemaPin)
- Credential, agent, and key-level revocation
- Mutual authentication with challenge-response
- Trust bundles for air-gapped and enterprise verification (v0.2.0)
API
Key Management
generate_key_pair() # → (private_key_pem, public_key_pem)
generate_key_id(public_key_pem) # → kid (hex SHA-256)
pem_to_jwk(public_key_pem, kid) # → JWK dict
jwk_to_pem(jwk) # → PEM string
Credentials
issue_credential(
private_key_pem, kid, issuer, agent_id, audience,
capabilities, constraints, delegation_chain, ttl_secs
)
# → compact JWT string
Verification
# Offline (with local discovery document)
verify_credential_offline(jwt, discovery, revocation, pin_store, audience, config)
# → VerificationResult(valid, agent_id, issuer, capabilities, key_pinning, ...)
# Online (auto-fetches discovery from issuer domain)
verify_credential(jwt, pin_store, audience, config)
Discovery & Revocation
build_discovery_document(entity, entity_type, public_keys, agents, max_delegation_depth)
build_revocation_document(entity)
add_revoked_credential(doc, jti, reason)
add_revoked_agent(doc, agent_id, reason)
add_revoked_key(doc, kid, reason)
Mutual Authentication
from agentpin import create_challenge, create_response, verify_response
challenge = create_challenge(verifier_credential)
response = create_response(challenge, private_key_pem, kid)
verify_response(response, challenge["nonce"], public_key_pem)
Key Pinning
from agentpin import KeyPinStore, PinningResult
store = KeyPinStore()
result = store.check_and_pin(domain, jwk) # PinningResult.FIRST_USE | MATCHED | CHANGED
store.add_key(domain, jwk) # allow key rotation
json_str = store.to_json() # persist
restored = KeyPinStore.from_json(json_str) # restore
Trust Bundles (v0.2.0)
from agentpin import (
create_trust_bundle,
find_bundle_discovery,
verify_credential_with_bundle,
save_trust_bundle,
load_trust_bundle,
)
# Create a bundle with pre-loaded discovery documents
bundle = create_trust_bundle()
bundle["documents"].append(discovery)
bundle["revocations"].append(revocation)
# Verify without any HTTP calls
result = verify_credential_with_bundle(
credential, bundle, pin_store=KeyPinStore(), audience="verifier.com"
)
# Save / load bundles to disk
save_trust_bundle(bundle, "trust-bundle.json")
bundle = load_trust_bundle("trust-bundle.json")
Configuration
from agentpin import VerifierConfig
config = VerifierConfig(
clock_skew_secs=60, # allow 60s time skew
max_ttl_secs=86400, # max 24h credential lifetime
)
Cross-Language Interoperability
Credentials issued by the Python package can be verified by the Rust and JavaScript implementations, and vice versa. All implementations use DER-encoded ECDSA signatures and identical JSON field names.
License
MIT — ThirdKey.ai
Release files for agentpin 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| agentpin-0.3.0.tar.gz | 42.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| agentpin-0.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 76.2 kB
Release files / agentpin-0.3.0.tar.gz
| Download URL | agentpin-0.3.0.tar.gz |
|---|---|
| Size | 42.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
9c6998b46ef855240d3143e0182c7470745bfab59207c50b1f56249e3499a2e6
|
|
BLAKE2b-256 checksum How to use checksums |
ab505971d1dbf9c3403dba871185eb0f16a454d5bf1ea47eaf7e5f760848bfe5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.3
|
Release files / agentpin-0.3.0-py3-none-any.whl
| Download URL | agentpin-0.3.0-py3-none-any.whl |
|---|---|
| Size | 34.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
5ddef1f127de80d86a426f157bf7b8860847fb3bd5ebab47e6025713bb43ce50
|
|
BLAKE2b-256 checksum How to use checksums |
220ea4bd2190afaf8d04de7b456d6a3b258165d7ff101befe4afc7d2640b3bd5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.3
|