Crates.io | atproto-xrpcs |
lib.rs | atproto-xrpcs |
version | 0.11.2 |
created_at | 2025-06-08 20:19:21.006106+00 |
updated_at | 2025-08-20 18:55:24.741212+00 |
description | Core building blocks for implementing AT Protocol XRPC services with JWT authorization |
homepage | |
repository | https://tangled.sh/@smokesignal.events/atproto-identity-rs |
max_upload_size | |
id | 1705235 |
size | 99,606 |
XRPC service framework for AT Protocol applications.
Build AT Protocol services with JWT authorization, DID resolution, and cryptographic identity verification middleware.
This crate does not provide standalone CLI tools. It serves as a foundational library for building XRPC services. See atproto-xrpcs-helloworld
for a complete example service implementation.
use atproto_xrpcs::authorization::ResolvingAuthorization;
use axum::{Json, Router, extract::Query, routing::get};
use serde::Deserialize;
use serde_json::json;
#[derive(Deserialize)]
struct HelloParams {
name: Option<String>,
}
async fn handle_hello(
params: Query<HelloParams>,
authorization: Option<ResolvingAuthorization>,
) -> Json<serde_json::Value> {
let name = params.name.as_deref().unwrap_or("World");
let message = if authorization.is_some() {
format!("Hello, authenticated {}!", name)
} else {
format!("Hello, {}!", name)
};
Json(json!({ "message": message }))
}
let app = Router::new()
.route("/xrpc/com.example.hello", get(handle_hello))
.with_state(your_web_context);
use atproto_xrpcs::authorization::ResolvingAuthorization;
async fn handle_secure_endpoint(
authorization: ResolvingAuthorization, // Required authorization
) -> Json<serde_json::Value> {
// The ResolvingAuthorization extractor automatically:
// 1. Validates the JWT token
// 2. Resolves the caller's DID document
// 3. Verifies the signature against the DID document
// 4. Provides access to caller identity information
let caller_did = authorization.subject();
Json(json!({"caller": caller_did, "status": "authenticated"}))
}
use atproto_xrpcs::errors::AuthorizationError;
use axum::{response::IntoResponse, http::StatusCode};
async fn protected_handler(
authorization: Result<ResolvingAuthorization, AuthorizationError>,
) -> impl IntoResponse {
match authorization {
Ok(auth) => (StatusCode::OK, "Access granted").into_response(),
Err(AuthorizationError::InvalidJWTToken { .. }) => {
(StatusCode::UNAUTHORIZED, "Invalid token").into_response()
}
Err(AuthorizationError::DIDDocumentResolutionFailed { .. }) => {
(StatusCode::FORBIDDEN, "Identity verification failed").into_response()
}
Err(_) => {
(StatusCode::INTERNAL_SERVER_ERROR, "Authorization error").into_response()
}
}
}
The ResolvingAuthorization
extractor implements:
MIT License