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.
Note: This project contains components extracted from the open-source smokesignal.events project, an AT Protocol event and RSVP management application. This library is released 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-oauth-aip- AT Protocol Identity Provider (AIP) OAuth workflow implementation for client applications.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.9.0"
atproto-record = "0.9.0"
atproto-oauth = "0.9.0"
atproto-oauth-aip = "0.9.0"
atproto-client = "0.9.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(())
}
OAuth Client Flow#
use atproto_oauth_aip::{OAuthClient, oauth_init, oauth_complete, session_exchange};
use atproto_oauth::storage::MemoryStorage;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let client = OAuthClient::new(
"https://your-app.com/client-id".to_string(),
Some("your-client-secret".to_string()),
"https://your-app.com/callback".to_string(),
);
let storage = MemoryStorage::new();
// Start OAuth flow
let (authorization_url, state) = oauth_init(
&client,
"alice.bsky.social",
&storage,
).await?;
println!("Visit: {}", authorization_url);
// After callback with code...
let access_token = oauth_complete(
&client,
"auth-code",
"state",
&storage,
).await?;
// Get AT Protocol session
let session = session_exchange(&client, &access_token, &storage).await?;
println!("Authenticated as: {} ({})", session.handle, session.did);
Ok(())
}
Command Line Tools#
The workspace includes 12 command-line tools across the crates. All CLI tools require the clap feature:
# Build with CLI support
cargo build --features clap --bins
# Identity operations (atproto-identity crate)
cargo run --features clap --bin atproto-identity-resolve -- alice.bsky.social
cargo run --features clap --bin atproto-identity-key -- generate p256
cargo run --features clap --bin atproto-identity-sign -- did:key:... data.json
cargo run --features clap --bin atproto-identity-validate -- did:key:... data.json signature
# Record operations (atproto-record crate)
cargo run --features clap --bin atproto-record-sign -- did:key:... did:plc:issuer record.json repository=did:plc:user collection=app.bsky.feed.post
cargo run --features clap --bin atproto-record-verify -- did:plc:issuer did:key:... signed_record.json repository=did:plc:user collection=app.bsky.feed.post
# Client operations (atproto-client crate)
cargo run --features clap --bin atproto-client-auth -- login alice.bsky.social password123
cargo run --features clap --bin atproto-client-app-password -- alice.bsky.social access_token /xrpc/com.atproto.repo.listRecords
cargo run --features clap --bin atproto-client-dpop -- alice.bsky.social did:key:... access_token /xrpc/com.atproto.repo.listRecords
# OAuth operations (atproto-oauth-axum crate)
cargo run --features clap --bin atproto-oauth-tool -- login did:key:... alice.bsky.social
# XRPC service (atproto-xrpcs-helloworld crate)
cargo run --bin atproto-xrpcs-helloworld
# Event streaming (atproto-jetstream crate)
cargo run --features clap --bin atproto-jetstream-consumer -- jetstream1.us-east.bsky.network dictionary.zstd
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.