A library for ATProtocol identities.
1# atproto-identity-rs
2
3A 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.
4
5**Note**: This project contains components 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.
6
7## Components
8
9### Core Libraries
10
11- **[`atproto-identity`](crates/atproto-identity/)** - Identity management with DID resolution and cryptographic operations. Includes 4 CLI tools for identity resolution, key management, signing, and validation.
12- **[`atproto-record`](crates/atproto-record/)** - AT Protocol record signature operations. Includes 2 CLI tools for signing and verifying records.
13- **[`atproto-oauth`](crates/atproto-oauth/)** - OAuth 2.0 implementation with AT Protocol security extensions including PKCE, DPoP, and JWT operations.
14- **[`atproto-oauth-aip`](crates/atproto-oauth-aip/)** - AT Protocol Identity Provider (AIP) OAuth workflow implementation for client applications.
15- **[`atproto-client`](crates/atproto-client/)** - HTTP client with DPoP authentication and repository operations. Includes 3 CLI tools for client authentication testing.
16
17### Web Framework Integration
18
19- **[`atproto-oauth-axum`](crates/atproto-oauth-axum/)** - Axum web handlers for OAuth endpoints. Includes 1 CLI tool for OAuth client testing.
20- **[`atproto-xrpcs`](crates/atproto-xrpcs/)** - XRPC service components with JWT authorization extractors.
21- **[`atproto-xrpcs-helloworld`](crates/atproto-xrpcs-helloworld/)** - Example XRPC service implementation with DID web support.
22
23### Event Streaming
24
25- **[`atproto-jetstream`](crates/atproto-jetstream/)** - WebSocket event stream consumer with compression support. Includes 1 CLI tool for event consumption.
26
27## Quick Start
28
29Add the crates to your `Cargo.toml`:
30
31```toml
32[dependencies]
33atproto-identity = "0.9.1"
34atproto-record = "0.9.1"
35atproto-oauth = "0.9.1"
36atproto-oauth-aip = "0.9.1"
37atproto-client = "0.9.1"
38# Add others as needed
39```
40
41### Basic Identity Resolution
42
43```rust
44use atproto_identity::resolve::{resolve_subject, create_resolver};
45
46#[tokio::main]
47async fn main() -> anyhow::Result<()> {
48 let http_client = reqwest::Client::new();
49 let dns_resolver = create_resolver(&[]);
50
51 let did = resolve_subject(&http_client, &dns_resolver, "alice.bsky.social").await?;
52 println!("Resolved DID: {}", did);
53
54 Ok(())
55}
56```
57
58### Record Signing
59
60```rust
61use atproto_identity::key::identify_key;
62use atproto_record::signature;
63use serde_json::json;
64
65#[tokio::main]
66async fn main() -> anyhow::Result<()> {
67 let signing_key = identify_key("did:key:zQ3shNzMp4oaaQ1gQRzCxMGXFrSW3NEM1M9T6KCY9eA7HhyEA")?;
68
69 let record = json!({
70 "$type": "app.bsky.feed.post",
71 "text": "Hello AT Protocol!",
72 "createdAt": "2024-01-01T00:00:00.000Z"
73 });
74
75 let signature_object = json!({
76 "issuer": "did:plc:issuer123",
77 "issuedAt": "2024-01-01T00:00:00.000Z"
78 });
79
80 let signed_record = signature::create(
81 &signing_key,
82 &record,
83 "did:plc:user123",
84 "app.bsky.feed.post",
85 signature_object,
86 ).await?;
87
88 Ok(())
89}
90```
91
92### XRPC Service
93
94```rust
95use atproto_xrpcs::authorization::ResolvingAuthorization;
96use axum::{Json, Router, extract::Query, routing::get};
97use serde::Deserialize;
98use serde_json::json;
99
100#[derive(Deserialize)]
101struct HelloParams {
102 subject: Option<String>,
103}
104
105async fn handle_hello(
106 params: Query<HelloParams>,
107 authorization: Option<ResolvingAuthorization>,
108) -> Json<serde_json::Value> {
109 let subject = params.subject.as_deref().unwrap_or("World");
110
111 let message = if let Some(auth) = authorization {
112 format!("Hello, authenticated {}! (caller: {})", subject, auth.subject())
113 } else {
114 format!("Hello, {}!", subject)
115 };
116
117 Json(json!({ "message": message }))
118}
119
120#[tokio::main]
121async fn main() -> anyhow::Result<()> {
122 let app = Router::new()
123 .route("/xrpc/com.example.hello", get(handle_hello))
124 .with_state(your_web_context);
125
126 let listener = tokio::net::TcpListener::bind("0.0.0.0:8080").await?;
127 axum::serve(listener, app).await?;
128
129 Ok(())
130}
131```
132
133### OAuth Client Flow
134
135```rust
136use atproto_oauth_aip::{OAuthClient, oauth_init, oauth_complete, session_exchange};
137use atproto_oauth::storage::MemoryStorage;
138
139#[tokio::main]
140async fn main() -> anyhow::Result<()> {
141 let client = OAuthClient::new(
142 "https://your-app.com/client-id".to_string(),
143 Some("your-client-secret".to_string()),
144 "https://your-app.com/callback".to_string(),
145 );
146
147 let storage = MemoryStorage::new();
148
149 // Start OAuth flow
150 let (authorization_url, state) = oauth_init(
151 &client,
152 "alice.bsky.social",
153 &storage,
154 ).await?;
155
156 println!("Visit: {}", authorization_url);
157
158 // After callback with code...
159 let access_token = oauth_complete(
160 &client,
161 "auth-code",
162 "state",
163 &storage,
164 ).await?;
165
166 // Get AT Protocol session
167 let session = session_exchange(&client, &access_token, &storage).await?;
168 println!("Authenticated as: {} ({})", session.handle, session.did);
169
170 Ok(())
171}
172```
173
174## Command Line Tools
175
176The workspace includes 12 command-line tools across the crates. All CLI tools require the `clap` feature:
177
178```bash
179# Build with CLI support
180cargo build --features clap --bins
181
182# Identity operations (atproto-identity crate)
183cargo run --features clap --bin atproto-identity-resolve -- alice.bsky.social
184cargo run --features clap --bin atproto-identity-key -- generate p256
185cargo run --features clap --bin atproto-identity-sign -- did:key:... data.json
186cargo run --features clap --bin atproto-identity-validate -- did:key:... data.json signature
187
188# Record operations (atproto-record crate)
189cargo run --features clap --bin atproto-record-sign -- did:key:... did:plc:issuer record.json repository=did:plc:user collection=app.bsky.feed.post
190cargo run --features clap --bin atproto-record-verify -- did:plc:issuer did:key:... signed_record.json repository=did:plc:user collection=app.bsky.feed.post
191
192# Client operations (atproto-client crate)
193cargo run --features clap --bin atproto-client-auth -- login alice.bsky.social password123
194cargo run --features clap --bin atproto-client-app-password -- alice.bsky.social access_token /xrpc/com.atproto.repo.listRecords
195cargo run --features clap --bin atproto-client-dpop -- alice.bsky.social did:key:... access_token /xrpc/com.atproto.repo.listRecords
196
197# OAuth operations (atproto-oauth-axum crate)
198cargo run --features clap --bin atproto-oauth-tool -- login did:key:... alice.bsky.social
199
200# XRPC service (atproto-xrpcs-helloworld crate)
201cargo run --bin atproto-xrpcs-helloworld
202
203# Event streaming (atproto-jetstream crate)
204cargo run --features clap --bin atproto-jetstream-consumer -- jetstream1.us-east.bsky.network dictionary.zstd
205```
206
207## Development
208
209```bash
210# Build all crates
211cargo build
212
213# Run all tests
214cargo test
215
216# Format and lint
217cargo fmt && cargo clippy
218
219# Generate documentation
220cargo doc --workspace --open
221```
222
223## License
224
225This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
226
227## Acknowledgments
228
229This library was extracted from the [smokesignal.events](https://tangled.sh/@smokesignal.events/smokesignal) project, an open-source AT Protocol event and RSVP management application.