Expand description
webfinger-rs is a transport-agnostic WebFinger implementation for Rust, centered on the
request and response types defined by RFC 7033 with first-party integrations for Reqwest,
Axum, and Actix Web.
WebFinger is used to discover information about people or other entities on the internet using
URI-based identifiers such as acct:carol@example.com. In practice, it is commonly used for
OpenID Connect Discovery, account discovery in federated systems like Mastodon and
ActivityPub, and for publishing identity-related metadata from your own site or service.
The crate keeps request parsing, JRD response construction, and framework adapters in one place so clients, servers, and tests use the same WebFinger types.
§Why use webfinger-rs?
- Reusable request and response types shaped around RFC 7033.
- Optional Reqwest client execution via
WebFingerRequest::execute_reqwest. - Optional Axum and Actix Web extractor/responder integrations.
- A permissive dual license (
MIT OR Apache-2.0) that fits typical library and application usage.
§Install
Start with the core crate, then enable the integration feature you need:
cargo add webfinger-rs
cargo add webfinger-rs --features reqwest
cargo add webfinger-rs --features axum
cargo add webfinger-rs --features actixThe related CLI tool, webfinger-cli, is useful for trying servers by hand:
cargo install webfinger-cli
webfinger acct:carol@example.com --rel http://webfinger.net/rel/avatar§Feature matrix
| Feature | What it enables |
|---|---|
| none | Core request/response types, builders, and URL conversion |
reqwest | Client execution helpers and Reqwest request/response conversions |
axum | WebFingerRequest extraction and WebFingerResponse responses in Axum via crate::axum |
actix | WebFingerRequest extraction and WebFingerResponse responses in Actix Web via crate::actix |
§Primary types
WebFingerRequestmodels the WebFinger query target, host, and optional relation filters. Build one directly for client requests, or extract one from an Axum or Actix handler.WebFingerResponsemodels the JSON Resource Descriptor returned by a WebFinger endpoint. Return one from server handlers or parse one from a Reqwest response.LinkandRelmodel JRD link objects and relation filters so servers can apply the same relation-filtering rules that clients request.ResourceandJrdUrivalidate URI-valued protocol fields before they enter requests or JRD responses.
§Protocol overview
A WebFinger query is an HTTPS GET against the well-known endpoint
WELL_KNOWN_PATH with a required resource parameter and, optionally, one or more rel
parameters. The resource parameter is the query target URI; builders and server extractors
reject relative references such as carol, /relative, ../x, and empty values.
A request built by this crate today for acct:carol@example.com filtered to the profile-page
relation looks like this:
GET https://example.com/.well-known/webfinger?resource=acct%3Acarol%40example.com&rel=http%3A%2F%2Fwebfinger.net%2Frel%2Fprofile-pageSee: RFC 7033 section 4.1 for the query-construction rules and percent-encoding details.
Server integrations leave routing and TLS at the framework boundary, then use WebFinger extractors for protocol parsing:
- mount the handler as
GETatWELL_KNOWN_PATHso the router rejects other paths and methods; - configure TLS and forwarded-proto handling at the server or reverse-proxy boundary; and
- let the
crate::axumorcrate::actixextractor validate the request host, query parameters, percent encoding, andresourceURI.
A successful JRD response might look like this:
{
"subject": "acct:carol@example.com",
"links": [
{
"rel": "http://webfinger.net/rel/profile-page",
"href": "https://example.com/users/carol"
}
]
}See: RFC 7033 section 4.4 for the JRD structure.
§Client quickstart
Enable the reqwest feature to execute WebFinger requests directly from the request type.
The current API expects an explicit host, which should normally match the resource host when the
resource URI has one.
use webfinger_rs::WebFingerRequest;
const PROFILE_PAGE_REL: &str = "http://webfinger.net/rel/profile-page";
const AVATAR_REL: &str = "http://webfinger.net/rel/avatar";
async fn example() -> Result<(), Box<dyn std::error::Error>> {
let request = WebFingerRequest::builder("acct:carol@example.com")?
.host("example.com")
.rel(PROFILE_PAGE_REL)
.rel(AVATAR_REL)
.build();
let response = request.execute_reqwest().await?;
println!("Subject: {}", response.subject);
for rel in [PROFILE_PAGE_REL, AVATAR_REL] {
if let Some(href) = response
.links
.iter()
.find(|link| link.rel.as_ref() == rel)
.and_then(|link| link.href.as_ref().map(|href| href.as_ref()))
{
println!("{rel}: {href}");
}
}
println!("{response}");
Ok(())
}§Axum quickstart
Enable the axum feature to extract WebFingerRequest from the incoming request and return
WebFingerResponse directly from your handler. Mount the handler at WELL_KNOWN_PATH.
See also crate::axum and the Axum example.
use axum::{http::StatusCode, routing::get, Router};
use webfinger_rs::{Link, Rel, WELL_KNOWN_PATH, WebFingerRequest, WebFingerResponse};
const SUBJECT: &str = "acct:carol@example.com";
const PROFILE_PAGE_REL: &str = "http://webfinger.net/rel/profile-page";
const AVATAR_REL: &str = "http://webfinger.net/rel/avatar";
const PROFILE_URL: &str = "https://example.com/users/carol";
const AVATAR_URL: &str = "https://example.com/media/carol.png";
const ROLE_PROPERTY: &str = "https://example.com/ns/account-role";
async fn webfinger(request: WebFingerRequest) -> axum::response::Result<WebFingerResponse> {
let subject = request.resource.to_string();
if subject != SUBJECT {
return Err((StatusCode::NOT_FOUND, "not found").into());
}
let mut links = Vec::new();
let profile_rel = Rel::new(PROFILE_PAGE_REL);
if request.rels.is_empty() || request.rels.contains(&profile_rel) {
links.push(
Link::builder(profile_rel)
.href(PROFILE_URL)
.title("en", "Carol's profile")
.build(),
);
}
let avatar_rel = Rel::new(AVATAR_REL);
if request.rels.is_empty() || request.rels.contains(&avatar_rel) {
links.push(
Link::builder(avatar_rel)
.href(AVATAR_URL)
.r#type("image/png")
.build(),
);
}
let response = WebFingerResponse::builder(subject)
.alias(PROFILE_URL)
.property(ROLE_PROPERTY, "maintainer")
.links(links)
.build();
Ok(response)
}
Router::new().route(WELL_KNOWN_PATH, get(webfinger))§Actix quickstart
Enable the actix feature to use the same request and response types in Actix Web handlers.
As with the Axum integration, the route path should be WELL_KNOWN_PATH. See also
crate::actix and the Actix example.
use actix_web::{App, web};
use webfinger_rs::{Link, Rel, WELL_KNOWN_PATH, WebFingerRequest, WebFingerResponse};
const SUBJECT: &str = "acct:carol@example.com";
const PROFILE_PAGE_REL: &str = "http://webfinger.net/rel/profile-page";
const AVATAR_REL: &str = "http://webfinger.net/rel/avatar";
const PROFILE_URL: &str = "https://example.com/users/carol";
const AVATAR_URL: &str = "https://example.com/media/carol.png";
const ROLE_PROPERTY: &str = "https://example.com/ns/account-role";
async fn webfinger(request: WebFingerRequest) -> actix_web::Result<WebFingerResponse> {
let subject = request.resource.to_string();
if subject != SUBJECT {
return Err(actix_web::error::ErrorNotFound("not found"));
}
let mut links = Vec::new();
let profile_rel = Rel::new(PROFILE_PAGE_REL);
if request.rels.is_empty() || request.rels.contains(&profile_rel) {
links.push(
Link::builder(profile_rel)
.href(PROFILE_URL)
.title("en", "Carol's profile")
.build(),
);
}
let avatar_rel = Rel::new(AVATAR_REL);
if request.rels.is_empty() || request.rels.contains(&avatar_rel) {
links.push(
Link::builder(avatar_rel)
.href(AVATAR_URL)
.r#type("image/png")
.build(),
);
}
let response = WebFingerResponse::builder(subject)
.alias(PROFILE_URL)
.property(ROLE_PROPERTY, "maintainer")
.links(links)
.build();
Ok(response)
}
App::new().route(WELL_KNOWN_PATH, web::get().to(webfinger))§Compatibility
The current first-party integration targets are:
- Reqwest
0.13 - Axum
0.8 - Actix Web
4
The crate is currently pre-0.1, so API and compatibility adjustments may still land in minor
releases while the integration surface settles. These version notes describe the currently
integrated crates, not a full protocol-compliance matrix.
§Limitations
- Client execution is currently implemented only for Reqwest.
- Server integrations are currently implemented only for Axum and Actix Web.
- The crate focuses on RFC 7033 request/response handling and framework integration, not a full identity stack around WebFinger.
- The crate docs aim to stay grounded in RFC 7033, but they document the current implementation rather than exhaustively enumerating every compliance detail.
See: RFC 7033 section 10.1 for the well-known path registration.
§Examples
Runnable examples are available in the repository:
cargo run -p webfinger-rs --example axum --features axumcargo run -p webfinger-rs --example actix --features actixcargo run -p webfinger-rs --example client --features reqwest
Run one server example first, then run the client example in another shell. The client example
queries https://localhost:3000, accepts the self-signed certificate generated by either server
example, and prints the profile-page and avatar links returned by the shared
WebFingerResponse type.
The server examples also work with the CLI. Query without --rel to get both links, or pass a
relation filter to narrow the returned links array:
webfinger acct:carol@localhost localhost:3000 --insecure
webfinger acct:carol@localhost localhost:3000 --insecure --rel http://webfinger.net/rel/profile-page
webfinger acct:carol@localhost localhost:3000 --insecure --rel http://webfinger.net/rel/avatar§License
Copyright (c) Josh McKinney
This project is licensed under either of:
- Apache License, Version 2.0 (LICENSE-APACHE or https://apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or https://opensource.org/licenses/MIT) at your option
Modules§
- actix
actix - Actix Web integration for WebFinger request extraction and JRD responses.
- axum
axum - Axum integration for WebFinger request extraction and JRD responses.
Structs§
- JrdUri
- A URI string used in a WebFinger JRD response.
- Link
- A link in the WebFinger response.
- Link
Builder - A builder for a WebFinger link.
- Rel
- Link relation type.
- Request
Builder - A builder for a WebFinger request.
- Resource
- A WebFinger resource URI.
- Response
Builder - A builder for a WebFinger response.
- Title
- A title in the WebFinger response.
- WebFinger
Request - A WebFinger request.
- WebFinger
Response - A WebFinger response.
Enums§
- Error
- Error type for this crate.
- Resource
Error - Errors that can occur while parsing a WebFinger resource URI.
Constants§
- WELL_
KNOWN_ PATH - The well-known path for WebFinger requests (
/.well-known/webfinger).