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.