atproto-identity#
A Rust library for AT Protocol identity resolution and management.
Overview#
atproto-identity provides comprehensive support for resolving and managing identities in the AT Protocol ecosystem. This library handles multiple DID (Decentralized Identifier) methods including did:plc and did:web, as well as AT Protocol handle resolution via both DNS and HTTP methods.
This project was extracted from the open-sourced Smokesignal project and is designed to be a standalone, reusable library for AT Protocol identity operations.
Features#
- Handle Resolution: Resolve AT Protocol handles to DIDs using DNS TXT records and HTTP well-known endpoints
- DID Document Retrieval: Fetch and parse DID documents for
did:plcanddid:webidentifiers - Multiple Resolution Methods: Supports both DNS and HTTP-based handle resolution with conflict detection
- Configurable DNS: Custom DNS nameserver support with fallback to system defaults
- Cryptographic Key Operations: Support for P-256 and K-256 key identification, signature validation, and signing
- Structured Logging: Built-in tracing support for debugging and monitoring
- Type Safety: Comprehensive error handling with structured error types
Supported DID Methods#
- did-method-plc: Public Ledger of Credentials DIDs via PLC directory
- did-method-web: Web-based DIDs following the did:web specification with URL conversion utilities
- ATProtocol Handle Resolution: AT Protocol handles (e.g.,
ngerakines.me) can be resolved to DIDs
Installation#
Add this to your Cargo.toml:
[dependencies]
atproto-identity = "0.2.0"
Usage#
Basic Handle Resolution#
use atproto_identity::resolve::{resolve_subject, create_resolver};
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let http_client = reqwest::Client::new();
let dns_resolver = create_resolver(&[]);
let did = resolve_subject(&http_client, &dns_resolver, "ngerakines.me").await?;
println!("Resolved DID: {}", did);
Ok(())
}
DID Document Retrieval#
use atproto_identity::{plc, web};
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let http_client = reqwest::Client::new();
// Query PLC DID document
let plc_doc = plc::query(&http_client, "plc.directory", "did:plc:example123").await?;
// Query Web DID document
let web_doc = web::query(&http_client, "did:web:example.com").await?;
// Convert Web DID to URL (for custom processing)
let did_url = web::did_web_to_url("did:web:example.com")?;
println!("DID document URL: {}", did_url);
Ok(())
}
Web DID URL Conversion#
The web module provides utilities for converting DID identifiers to their HTTPS document URLs:
use atproto_identity::web;
fn main() -> anyhow::Result<()> {
// Convert simple hostname DID
let url = web::did_web_to_url("did:web:example.com")?;
// Returns: "https://example.com/.well-known/did.json"
// Convert DID with path components
let url = web::did_web_to_url("did:web:example.com:path:subpath")?;
// Returns: "https://example.com/path/subpath/did.json"
Ok(())
}
Cryptographic Key Operations#
The key module provides utilities for working with cryptographic keys:
use atproto_identity::key::{identify_key, validate, KeyType};
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Identify a key from a DID key string
let key_data = identify_key("did:key:zQ3shNzMp4oaaQ1gQRzCxMGXFrSW3NEM1M9T6KCY9eA7HhyEA")?;
match key_data.0 {
KeyType::K256Public => println!("K-256 public key"),
KeyType::P256Public => println!("P-256 public key"),
KeyType::K256Private => println!("K-256 private key"),
KeyType::P256Private => println!("P-256 private key"),
}
// Validate a signature (example with dummy data)
let content = b"hello world";
let signature = vec![0u8; 64]; // Replace with actual signature
validate(&key_data, &signature, content)?;
Ok(())
}
Configuration#
The library supports various configuration options through environment variables:
# Custom PLC directory hostname
export PLC_HOSTNAME=plc.directory
# Custom DNS nameservers (semicolon-separated)
export DNS_NAMESERVERS=8.8.8.8;1.1.1.1
# Custom CA certificate bundles (semicolon-separated paths)
export CERTIFICATE_BUNDLES=/path/to/cert1.pem;/path/to/cert2.pem
# Custom User-Agent string
export USER_AGENT="my-app/1.0"
Command Line Tool#
The library includes a command-line tool for testing and resolution:
# Install the binary
cargo install --path .
# Resolve a handle to DID
atproto-identity-resolve ngerakines.me
# Get full DID document
atproto-identity-resolve --did-document ngerakines.me
Architecture#
The library is organized into several modules:
- resolve: Core resolution logic for handles and DIDs
- plc: PLC directory client for
did:plcresolution - web: Web DID client for
did:webresolution and URL conversion - model: Data structures for DID documents and AT Protocol entities
- validation: Input validation for handles and DIDs
- config: Configuration management and environment variable handling
- errors: Structured error types following project conventions
- key: Cryptographic key operations including signature validation and key identification for P-256 and K-256 curves
Error Handling#
All errors follow a structured format:
error-atproto-identity-<domain>-<number> <message>: <details>
Examples:
error-atproto-identity-resolve-1 Multiple DIDs resolved for methoderror-atproto-identity-plc-1 HTTP request failed: https://plc.directory/did:plc:example Not Founderror-did-web-1 Invalid DID format: missing 'did:web:' prefix
Contributing#
Contributions are welcome! Please ensure that:
- All tests pass:
cargo test - Code is properly formatted:
cargo fmt - No linting issues:
cargo clippy - New functionality includes appropriate tests
License#
This project is licensed under the MIT License. See the LICENSE file for details.
Acknowledgments#
This library was extracted from the Smokesignal project, an open-source event and RSVP management and discovery application.