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-record`](crates/atproto-record/)** - Cryptographic signature operations for AT Protocol records using IPLD DAG-CBOR serialization with AT-URI parsing support. *Includes 2 CLI tools.* 15- **[`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.* 16 17### Authentication & Authorization 18 19- **[`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.* 20- **[`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. 21- **[`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.* 22 23### Client & Service Development 24 25- **[`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.* 26- **[`atproto-xrpcs`](crates/atproto-xrpcs/)** - XRPC service framework providing JWT authorization extractors, DID resolution integration, and Axum middleware for building AT Protocol services. 27- **[`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.* 28 29### Real-time Event Processing 30 31- **[`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.* 32 33## Quick Start 34 35Add the crates to your `Cargo.toml`: 36 37```toml 38[dependencies] 39atproto-identity = "0.13.0" 40atproto-record = "0.13.0" 41atproto-lexicon = "0.13.0" 42atproto-oauth = "0.13.0" 43atproto-oauth-aip = "0.13.0" 44atproto-client = "0.13.0" 45# Add others as needed 46``` 47 48### Basic Identity Resolution 49 50```rust 51use atproto_identity::resolve::{resolve_subject, create_resolver}; 52 53#[tokio::main] 54async fn main() -> anyhow::Result<()> { 55 let http_client = reqwest::Client::new(); 56 let dns_resolver = create_resolver(&[]); 57 58 let did = resolve_subject(&http_client, &dns_resolver, "alice.bsky.social").await?; 59 println!("Resolved DID: {}", did); 60 61 Ok(()) 62} 63``` 64 65### Lexicon Resolution 66 67```rust 68use atproto_lexicon::resolve::{DefaultLexiconResolver, LexiconResolver}; 69use atproto_identity::resolve::HickoryDnsResolver; 70 71#[tokio::main] 72async fn main() -> anyhow::Result<()> { 73 let http_client = reqwest::Client::new(); 74 let dns_resolver = HickoryDnsResolver::create_resolver(&[]); 75 let resolver = DefaultLexiconResolver::new(http_client, dns_resolver); 76 77 // Resolve a lexicon schema 78 let lexicon = resolver.resolve("app.bsky.feed.post").await?; 79 println!("Lexicon schema: {}", serde_json::to_string_pretty(&lexicon)?); 80 81 Ok(()) 82} 83``` 84 85### Record Signing 86 87```rust 88use atproto_identity::key::identify_key; 89use atproto_record::signature; 90use serde_json::json; 91 92#[tokio::main] 93async fn main() -> anyhow::Result<()> { 94 let signing_key = identify_key("did:key:zQ3shNzMp4oaaQ1gQRzCxMGXFrSW3NEM1M9T6KCY9eA7HhyEA")?; 95 96 let record = json!({ 97 "$type": "app.bsky.feed.post", 98 "text": "Hello AT Protocol!", 99 "createdAt": "2024-01-01T00:00:00.000Z" 100 }); 101 102 let signature_object = json!({ 103 "issuer": "did:plc:issuer123", 104 "issuedAt": "2024-01-01T00:00:00.000Z" 105 }); 106 107 let signed_record = signature::create( 108 &signing_key, 109 &record, 110 "did:plc:user123", 111 "app.bsky.feed.post", 112 signature_object, 113 ).await?; 114 115 Ok(()) 116} 117``` 118 119### XRPC Service 120 121```rust 122use atproto_xrpcs::authorization::ResolvingAuthorization; 123use axum::{Json, Router, extract::Query, routing::get}; 124use serde::Deserialize; 125use serde_json::json; 126 127#[derive(Deserialize)] 128struct HelloParams { 129 subject: Option<String>, 130} 131 132async fn handle_hello( 133 params: Query<HelloParams>, 134 authorization: Option<ResolvingAuthorization>, 135) -> Json<serde_json::Value> { 136 let subject = params.subject.as_deref().unwrap_or("World"); 137 138 let message = if let Some(auth) = authorization { 139 format!("Hello, authenticated {}! (caller: {})", subject, auth.subject()) 140 } else { 141 format!("Hello, {}!", subject) 142 }; 143 144 Json(json!({ "message": message })) 145} 146 147#[tokio::main] 148async fn main() -> anyhow::Result<()> { 149 let app = Router::new() 150 .route("/xrpc/com.example.hello", get(handle_hello)) 151 .with_state(your_web_context); 152 153 let listener = tokio::net::TcpListener::bind("0.0.0.0:8080").await?; 154 axum::serve(listener, app).await?; 155 156 Ok(()) 157} 158``` 159 160### OAuth Client Flow 161 162```rust 163use atproto_oauth_aip::{OAuthClient, oauth_init, oauth_complete, session_exchange}; 164use atproto_oauth::storage::MemoryStorage; 165 166#[tokio::main] 167async fn main() -> anyhow::Result<()> { 168 let client = OAuthClient::new( 169 "https://your-app.com/client-id".to_string(), 170 Some("your-client-secret".to_string()), 171 "https://your-app.com/callback".to_string(), 172 ); 173 174 let storage = MemoryStorage::new(); 175 176 // Start OAuth flow 177 let (authorization_url, state) = oauth_init( 178 &client, 179 "alice.bsky.social", 180 &storage, 181 ).await?; 182 183 println!("Visit: {}", authorization_url); 184 185 // After callback with code... 186 let access_token = oauth_complete( 187 &client, 188 "auth-code", 189 "state", 190 &storage, 191 ).await?; 192 193 // Get AT Protocol session 194 let session = session_exchange(&client, &access_token, &storage).await?; 195 println!("Authenticated as: {} ({})", session.handle, session.did); 196 197 Ok(()) 198} 199``` 200 201## Command Line Tools 202 203The 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: 204 205```bash 206# Build with CLI support 207cargo build --features clap --bins 208 209# Identity operations (atproto-identity crate) 210cargo run --features clap --bin atproto-identity-resolve -- alice.bsky.social 211cargo run --features clap --bin atproto-identity-key -- generate p256 212cargo run --features clap --bin atproto-identity-sign -- did:key:... data.json 213cargo run --features clap --bin atproto-identity-validate -- did:key:... data.json signature 214 215# Record operations (atproto-record crate) 216cargo run --features clap --bin atproto-record-sign -- did:key:... did:plc:issuer record.json repository=did:plc:user collection=app.bsky.feed.post 217cargo run --features clap --bin atproto-record-verify -- did:plc:issuer did:key:... signed_record.json repository=did:plc:user collection=app.bsky.feed.post 218 219# Lexicon operations (atproto-lexicon crate) 220cargo run --features clap,hickory-dns --bin atproto-lexicon-resolve -- app.bsky.feed.post 221 222# Client operations (atproto-client crate) 223cargo run --features clap --bin atproto-client-auth -- login alice.bsky.social password123 224cargo run --features clap --bin atproto-client-app-password -- alice.bsky.social access_token /xrpc/com.atproto.repo.listRecords 225cargo run --features clap --bin atproto-client-dpop -- alice.bsky.social did:key:... access_token /xrpc/com.atproto.repo.listRecords 226 227# OAuth operations (atproto-oauth crate) 228cargo run --features clap --bin atproto-oauth-service-token -- [service-token-args] 229 230# OAuth operations (atproto-oauth-axum crate) 231cargo run --features clap --bin atproto-oauth-tool -- login did:key:... alice.bsky.social 232 233# XRPC service (atproto-xrpcs-helloworld crate) 234cargo run --bin atproto-xrpcs-helloworld 235 236# Event streaming (atproto-jetstream crate) 237cargo run --features clap --bin atproto-jetstream-consumer -- jetstream1.us-east.bsky.network dictionary.zstd 238``` 239 240## Development 241 242```bash 243# Build all crates 244cargo build 245 246# Run all tests 247cargo test 248 249# Format and lint 250cargo fmt && cargo clippy 251 252# Generate documentation 253cargo doc --workspace --open 254``` 255 256## License 257 258This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. 259 260## Architecture 261 262These components are designed to work together as building blocks for AT Protocol applications: 263 264- **Identity Layer**: `atproto-identity` provides the foundation for DID resolution and cryptographic operations 265- **Authentication Layer**: `atproto-oauth*` crates handle complete OAuth 2.0 flows with AT Protocol security extensions 266- **Application Layer**: `atproto-client` and `atproto-xrpcs*` enable client applications and service development 267- **Data Layer**: `atproto-record` handles record signing and verification with proper IPLD serialization 268- **Event Layer**: `atproto-jetstream` provides real-time event processing capabilities 269 270## Use Cases 271 272This workspace enables development of: 273 274- **AT Protocol Identity Providers (AIPs)** - Complete OAuth servers with DID-based authentication 275- **Personal Data Servers (PDS)** - XRPC services with JWT authorization and repository management 276- **AT Protocol Clients** - Applications that authenticate and interact with AT Protocol services 277- **Event Processing Systems** - Real-time processors for AT Protocol repository events 278- **Development Tools** - CLI utilities for testing, debugging, and managing AT Protocol identities 279 280## Contributing 281 282Contributions are welcome! This project follows standard Rust development practices: 283 2841. Fork this repository 2852. Create a feature branch 2863. Run tests: `cargo test` 2874. Run linting: `cargo fmt && cargo clippy` 2885. Submit a pull request 289 290## Acknowledgments 291 292Parts 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.