atproto-identity-rs#
A comprehensive collection of Rust crates for building AT Protocol applications. This workspace provides identity management, record operations, OAuth 2.0 flows, HTTP client operations, XRPC services, and event streaming capabilities.
Parts of this project were extracted from the open-source smokesignal.events project and are licensed under the MIT license.
Components#
Core Libraries#
atproto-identity- Identity management with DID resolution and cryptographic operations. Includes 4 CLI tools for identity resolution, key management, signing, and validation.atproto-record- AT Protocol record signature operations. Includes 2 CLI tools for signing and verifying records.atproto-oauth- OAuth 2.0 implementation with AT Protocol security extensions including PKCE, DPoP, and JWT operations.atproto-client- HTTP client with DPoP authentication and repository operations. Includes 3 CLI tools for client authentication testing.
Web Framework Integration#
atproto-oauth-axum- Axum web handlers for OAuth endpoints. Includes 1 CLI tool for OAuth client testing.atproto-xrpcs- XRPC service components with JWT authorization extractors.atproto-xrpcs-helloworld- Example XRPC service implementation with DID web support.
Event Streaming#
atproto-jetstream- WebSocket event stream consumer with compression support. Includes 1 CLI tool for event consumption.
Quick Start#
Add the crates to your Cargo.toml:
[dependencies]
atproto-identity = "0.6.0"
atproto-record = "0.6.0"
atproto-oauth = "0.6.0"
atproto-client = "0.6.0"
# Add others as needed
Basic Identity 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, "alice.bsky.social").await?;
println!("Resolved DID: {}", did);
Ok(())
}
Record Signing#
use atproto_identity::key::identify_key;
use atproto_record::signature;
use serde_json::json;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let signing_key = identify_key("did:key:zQ3shNzMp4oaaQ1gQRzCxMGXFrSW3NEM1M9T6KCY9eA7HhyEA")?;
let record = json!({
"$type": "app.bsky.feed.post",
"text": "Hello AT Protocol!",
"createdAt": "2024-01-01T00:00:00.000Z"
});
let signature_object = json!({
"issuer": "did:plc:issuer123",
"issuedAt": "2024-01-01T00:00:00.000Z"
});
let signed_record = signature::create(
&signing_key,
&record,
"did:plc:user123",
"app.bsky.feed.post",
signature_object,
).await?;
Ok(())
}
XRPC Service#
use atproto_xrpcs::authorization::ResolvingAuthorization;
use axum::{Json, Router, extract::Query, routing::get};
use serde::Deserialize;
use serde_json::json;
#[derive(Deserialize)]
struct HelloParams {
subject: Option<String>,
}
async fn handle_hello(
params: Query<HelloParams>,
authorization: Option<ResolvingAuthorization>,
) -> Json<serde_json::Value> {
let subject = params.subject.as_deref().unwrap_or("World");
let message = if let Some(auth) = authorization {
format!("Hello, authenticated {}! (caller: {})", subject, auth.subject())
} else {
format!("Hello, {}!", subject)
};
Json(json!({ "message": message }))
}
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let app = Router::new()
.route("/xrpc/com.example.hello", get(handle_hello))
.with_state(your_web_context);
let listener = tokio::net::TcpListener::bind("0.0.0.0:8080").await?;
axum::serve(listener, app).await?;
Ok(())
}
Command Line Tools#
The workspace includes 12 command-line tools across the crates:
# Identity operations
cargo run --bin atproto-identity-resolve alice.bsky.social
cargo run --bin atproto-identity-key generate p256
cargo run --bin atproto-identity-sign did:key:... data.json
cargo run --bin atproto-identity-validate did:key:... data.json signature
# Record operations
cargo run --bin atproto-record-sign did:key:... did:plc:issuer record.json repo=did:plc:user collection=app.bsky.feed.post
cargo run --bin atproto-record-verify did:plc:issuer did:key:... signed_record.json repo=did:plc:user collection=app.bsky.feed.post
# Client operations
cargo run --bin atproto-client-auth --handle alice.bsky.social
cargo run --bin atproto-client-app-password --identifier alice.bsky.social
cargo run --bin atproto-client-dpop --private-key did:key:... --access-token token --url https://pds.example.com/xrpc/endpoint
# OAuth operations
EXTERNAL_BASE=localhost:8080 cargo run --bin atproto-oauth-tool login did:key:... alice.bsky.social
# XRPC service
EXTERNAL_BASE=localhost:8080 SERVICE_KEY=did:key:... cargo run --bin atproto-xrpcs-helloworld
# Event streaming
cargo run --bin atproto-jetstream-consumer --hostname jetstream1.us-east.bsky.network --collections app.bsky.feed.post
Development#
# Build all crates
cargo build
# Run all tests
cargo test
# Format and lint
cargo fmt && cargo clippy
# Generate documentation
cargo doc --workspace --open
License#
This project is licensed under the MIT License - see the LICENSE file for details.
Acknowledgments#
This library was extracted from the smokesignal.events project, an open-source AT Protocol event and RSVP management application.