A library for ATProtocol identities.
1# AT Protocol Identity Rust Components 2 3A comprehensive collection of Rust components for creating AT Protocol applications. This workspace provides essential building blocks for identity management, record operations, OAuth 2.0 authentication flows, HTTP client operations, XRPC services, and real-time event streaming. 4 5**Origin**: Parts of this project were extracted from the open-source [smokesignal.events](https://tangled.sh/@smokesignal.events/smokesignal) project, an AT Protocol event and RSVP management application. This library is released under the MIT license to enable broader AT Protocol ecosystem development. 6 7## Components 8 9This workspace contains 10 specialized crates that work together to provide complete AT Protocol application development capabilities: 10 11### Identity & Cryptography 12 13- **[`atproto-identity`](crates/atproto-identity/)** - Core identity management with multi-method DID resolution (plc, web, key), DNS/HTTP handle resolution, and P-256/P-384/K-256 cryptographic operations. *Includes 4 CLI tools.* 14- **[`atproto-attestation`](crates/atproto-attestation/)** - CID-first attestation utilities for creating and verifying cryptographic signatures on AT Protocol records, supporting both inline and remote attestation workflows. *Includes 2 CLI tools.* 15- **[`atproto-record`](crates/atproto-record/)** - Record utilities including TID generation, AT-URI parsing, datetime formatting, and CID generation using IPLD DAG-CBOR serialization. *Includes 1 CLI tool.* 16- **[`atproto-lexicon`](crates/atproto-lexicon/)** - Lexicon schema resolution and validation for AT Protocol, supporting recursive resolution, NSID validation, and DNS-based lexicon discovery. *Includes 1 CLI tool.* 17 18### Authentication & Authorization 19 20- **[`atproto-oauth`](crates/atproto-oauth/)** - Complete OAuth 2.0 implementation with AT Protocol security extensions including DPoP (RFC 9449), PKCE (RFC 7636), JWT operations, and secure storage abstractions. *Includes 1 CLI tool.* 21- **[`atproto-oauth-aip`](crates/atproto-oauth-aip/)** - OAuth AIP (Identity Provider) implementation providing complete authorization code flow with PAR, token exchange, and AT Protocol session management. 22- **[`atproto-oauth-axum`](crates/atproto-oauth-axum/)** - Production-ready Axum web handlers for OAuth endpoints including authorization callbacks, JWKS endpoints, and client metadata. *Includes 1 CLI tool.* 23 24### Client & Service Development 25 26- **[`atproto-client`](crates/atproto-client/)** - HTTP client library supporting multiple authentication methods (DPoP, Bearer tokens, sessions) with native XRPC protocol operations and repository management. *Includes 3 CLI tools.* 27- **[`atproto-xrpcs`](crates/atproto-xrpcs/)** - XRPC service framework providing JWT authorization extractors, DID resolution integration, and Axum middleware for building AT Protocol services. 28- **[`atproto-xrpcs-helloworld`](crates/atproto-xrpcs-helloworld/)** - Complete example XRPC service demonstrating DID:web identity, service document generation, and JWT authentication patterns. *Includes 1 service binary.* 29 30### Real-time Event Processing 31 32- **[`atproto-jetstream`](crates/atproto-jetstream/)** - WebSocket consumer for AT Protocol Jetstream events with Zstandard compression, automatic reconnection, and configurable event filtering. *Includes 1 CLI tool.* 33 34## Quick Start 35 36Add the crates to your `Cargo.toml`: 37 38```toml 39[dependencies] 40atproto-identity = "0.13.0" 41atproto-attestation = "0.13.0" 42atproto-record = "0.13.0" 43atproto-lexicon = "0.13.0" 44atproto-oauth = "0.13.0" 45atproto-oauth-aip = "0.13.0" 46atproto-client = "0.13.0" 47# Add others as needed 48``` 49 50### Basic Identity Resolution 51 52```rust 53use atproto_identity::resolve::{resolve_subject, create_resolver}; 54 55#[tokio::main] 56async fn main() -> anyhow::Result<()> { 57 let http_client = reqwest::Client::new(); 58 let dns_resolver = create_resolver(&[]); 59 60 let did = resolve_subject(&http_client, &dns_resolver, "alice.bsky.social").await?; 61 println!("Resolved DID: {}", did); 62 63 Ok(()) 64} 65``` 66 67### Lexicon Resolution 68 69```rust 70use atproto_lexicon::resolve::{DefaultLexiconResolver, LexiconResolver}; 71use atproto_identity::resolve::HickoryDnsResolver; 72 73#[tokio::main] 74async fn main() -> anyhow::Result<()> { 75 let http_client = reqwest::Client::new(); 76 let dns_resolver = HickoryDnsResolver::create_resolver(&[]); 77 let resolver = DefaultLexiconResolver::new(http_client, dns_resolver); 78 79 // Resolve a lexicon schema 80 let lexicon = resolver.resolve("app.bsky.feed.post").await?; 81 println!("Lexicon schema: {}", serde_json::to_string_pretty(&lexicon)?); 82 83 Ok(()) 84} 85``` 86 87### Record Signing 88 89```rust 90use atproto_identity::key::{identify_key, to_public}; 91use atproto_attestation::{ 92 create_inline_attestation, verify_all_signatures, VerificationStatus, 93 input::{AnyInput, PhantomSignature} 94}; 95use serde_json::json; 96 97#[tokio::main] 98async fn main() -> anyhow::Result<()> { 99 let private_key = identify_key("did:key:zQ3shNzMp4oaaQ1gQRzCxMGXFrSW3NEM1M9T6KCY9eA7HhyEA")?; 100 let public_key = to_public(&private_key)?; 101 let key_reference = format!("{}", &public_key); 102 let repository_did = "did:plc:repo123"; 103 104 let record = json!({ 105 "$type": "app.bsky.feed.post", 106 "text": "Hello AT Protocol!", 107 "createdAt": "2024-01-01T00:00:00.000Z" 108 }); 109 110 let sig_metadata = json!({ 111 "$type": "com.example.inlineSignature", 112 "key": &key_reference, 113 "issuer": "did:plc:issuer123", 114 "issuedAt": "2024-01-01T00:00:00.000Z" 115 }); 116 117 let signed_record = create_inline_attestation::<PhantomSignature, PhantomSignature>( 118 AnyInput::Json(record), 119 AnyInput::Json(sig_metadata), 120 repository_did, 121 &private_key 122 )?; 123 124 let reports = verify_all_signatures(&signed_record, repository_did, None).await?; 125 assert!(reports.iter().all(|report| matches!(report.status, VerificationStatus::Valid { .. }))); 126 127 Ok(()) 128} 129``` 130 131### XRPC Service 132 133```rust 134use atproto_xrpcs::authorization::Authorization; 135use axum::{Json, Router, extract::Query, routing::get}; 136use serde::Deserialize; 137use serde_json::json; 138 139#[derive(Deserialize)] 140struct HelloParams { 141 subject: Option<String>, 142} 143 144async fn handle_hello( 145 params: Query<HelloParams>, 146 authorization: Option<Authorization>, 147) -> Json<serde_json::Value> { 148 let subject = params.subject.as_deref().unwrap_or("World"); 149 150 let message = if let Some(auth) = authorization { 151 format!("Hello, authenticated {}! (caller: {})", subject, auth.subject()) 152 } else { 153 format!("Hello, {}!", subject) 154 }; 155 156 Json(json!({ "message": message })) 157} 158 159#[tokio::main] 160async fn main() -> anyhow::Result<()> { 161 let app = Router::new() 162 .route("/xrpc/com.example.hello", get(handle_hello)) 163 .with_state(your_web_context); 164 165 let listener = tokio::net::TcpListener::bind("0.0.0.0:8080").await?; 166 axum::serve(listener, app).await?; 167 168 Ok(()) 169} 170``` 171 172### OAuth Client Flow 173 174```rust 175use atproto_oauth_aip::{OAuthClient, oauth_init, oauth_complete, session_exchange}; 176use atproto_oauth::storage::MemoryStorage; 177 178#[tokio::main] 179async fn main() -> anyhow::Result<()> { 180 let client = OAuthClient::new( 181 "https://your-app.com/client-id".to_string(), 182 Some("your-client-secret".to_string()), 183 "https://your-app.com/callback".to_string(), 184 ); 185 186 let storage = MemoryStorage::new(); 187 188 // Start OAuth flow 189 let (authorization_url, state) = oauth_init( 190 &client, 191 "alice.bsky.social", 192 &storage, 193 ).await?; 194 195 println!("Visit: {}", authorization_url); 196 197 // After callback with code... 198 let access_token = oauth_complete( 199 &client, 200 "auth-code", 201 "state", 202 &storage, 203 ).await?; 204 205 // Get AT Protocol session 206 let session = session_exchange(&client, &access_token, &storage).await?; 207 println!("Authenticated as: {} ({})", session.handle, session.did); 208 209 Ok(()) 210} 211``` 212 213## Command Line Tools 214 215The workspace includes 13 command-line tools across multiple crates, providing ready-to-use utilities for AT Protocol development and testing. All CLI tools require the `clap` feature: 216 217```bash 218# Build with CLI support 219cargo build --features clap --bins 220 221# Identity operations (atproto-identity crate) 222cargo run --features clap --bin atproto-identity-resolve -- alice.bsky.social 223cargo run --features clap --bin atproto-identity-key -- generate p256 224cargo run --features clap --bin atproto-identity-sign -- did:key:... data.json 225cargo run --features clap --bin atproto-identity-validate -- did:key:... data.json signature 226 227# Attestation operations (atproto-attestation crate) 228cargo run --package atproto-attestation --features clap,tokio --bin atproto-attestation-sign -- inline record.json did:key:... metadata.json 229cargo run --package atproto-attestation --features clap,tokio --bin atproto-attestation-verify -- signed_record.json 230 231# Record operations (atproto-record crate) 232cat record.json | cargo run --features clap --bin atproto-record-cid 233 234# Lexicon operations (atproto-lexicon crate) 235cargo run --features clap,hickory-dns --bin atproto-lexicon-resolve -- app.bsky.feed.post 236 237# Client operations (atproto-client crate) 238cargo run --features clap --bin atproto-client-auth -- login alice.bsky.social password123 239cargo run --features clap --bin atproto-client-app-password -- alice.bsky.social access_token /xrpc/com.atproto.repo.listRecords 240cargo run --features clap --bin atproto-client-dpop -- alice.bsky.social did:key:... access_token /xrpc/com.atproto.repo.listRecords 241 242# OAuth operations (atproto-oauth crate) 243cargo run --features clap --bin atproto-oauth-service-token -- [service-token-args] 244 245# OAuth operations (atproto-oauth-axum crate) 246cargo run --features clap --bin atproto-oauth-tool -- login did:key:... alice.bsky.social 247 248# XRPC service (atproto-xrpcs-helloworld crate) 249cargo run --bin atproto-xrpcs-helloworld 250 251# Event streaming (atproto-jetstream crate) 252cargo run --features clap --bin atproto-jetstream-consumer -- jetstream1.us-east.bsky.network dictionary.zstd 253``` 254 255## Development 256 257```bash 258# Build all crates 259cargo build 260 261# Run all tests 262cargo test 263 264# Format and lint 265cargo fmt && cargo clippy 266 267# Generate documentation 268cargo doc --workspace --open 269``` 270 271## License 272 273This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. 274 275## Architecture 276 277These components are designed to work together as building blocks for AT Protocol applications: 278 279- **Identity Layer**: `atproto-identity` provides the foundation for DID resolution and cryptographic operations 280- **Authentication Layer**: `atproto-oauth*` crates handle complete OAuth 2.0 flows with AT Protocol security extensions 281- **Application Layer**: `atproto-client` and `atproto-xrpcs*` enable client applications and service development 282- **Data Layer**: `atproto-record` handles record signing and verification with proper IPLD serialization 283- **Event Layer**: `atproto-jetstream` provides real-time event processing capabilities 284 285## Use Cases 286 287This workspace enables development of: 288 289- **AT Protocol Identity Providers (AIPs)** - Complete OAuth servers with DID-based authentication 290- **Personal Data Servers (PDS)** - XRPC services with JWT authorization and repository management 291- **AT Protocol Clients** - Applications that authenticate and interact with AT Protocol services 292- **Event Processing Systems** - Real-time processors for AT Protocol repository events 293- **Development Tools** - CLI utilities for testing, debugging, and managing AT Protocol identities 294 295## Contributing 296 297Contributions are welcome! This project follows standard Rust development practices: 298 2991. Fork this repository 3002. Create a feature branch 3013. Run tests: `cargo test` 3024. Run linting: `cargo fmt && cargo clippy` 3035. Submit a pull request 304 305## Acknowledgments 306 307Parts of this project were extracted from the [smokesignal.events](https://tangled.sh/@smokesignal.events/smokesignal) project, an open-source AT Protocol event and RSVP management application. This extraction enables broader community use and contribution to AT Protocol tooling in Rust.