atproto-xrpcs#
XRPC service components library for AT Protocol with JWT authorization.
Overview#
atproto-xrpcs provides foundational components for building AT Protocol XRPC services. This library offers JWT-based authorization extractors that integrate with Axum web handlers, enabling secure XRPC endpoints with automatic DID document verification.
This is a library-only crate that provides reusable components for XRPC service development. For a complete example service implementation, see the atproto-xrpcs-helloworld crate.
Features#
- JWT authorization extractors for Axum web handlers
- Automatic DID document verification for caller identities
- Structured error handling with detailed error codes
- Native Axum integration for HTTP handlers
- Identity resolution support for AT Protocol
Usage#
Basic XRPC Service#
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);
JWT Authorization#
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"}))
}
Error Handling#
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()
}
}
}
Authorization Flow#
The ResolvingAuthorization extractor implements:
- JWT extraction from HTTP Authorization headers
- Token validation (signature and claims structure)
- DID resolution for the token issuer
- Signature verification against DID document public keys
- Identity confirmation and authorization scope validation
License#
MIT License