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.