Skip to content
XID

sdk/rust

Async Rust server SDK for networkless JWT verification, request authentication, and webhook signature validation.

Status

Implemented and verified locally. Real IdP round-trip verification (JWKS fetch, token sign/verify against a live XID instance) has not been performed yet and must be completed before production use.

XID publishes no packages to any registry. This SDK is distributed as source in the XID repository; use it from a checkout of the repository.

Request authentication is Bearer-only by default. An application-owned JWT cookie is read only when its exact name is configured. The opaque __Host-xid.rt.* Core cookie is never scanned or verified locally; exchange it by forwarding the complete Cookie header to exact same-origin POST /v1/sessions/token with redirects disabled, and accept only a response containing the token field.

Install

Add to Cargo.toml:

[dependencies]
xid = { path = "../sdk/rust" }
tokio = { version = "1", features = ["full"] }

Quick start

use std::sync::Arc;
use xid::{XidClient, XidClientConfig, AuthState};

#[tokio::main]
async fn main() {
    let config = XidClientConfig::new("https://xid.dev")
        .with_audience("your-client-id");

    let client = Arc::new(XidClient::new(config).expect("build client"));

    match client.verify_token("eyJ...").await {
        Ok(verified) => {
            println!("user: {}", verified.claims.sub);
            println!("email: {:?}", verified.claims.email);
        }
        Err(e) => eprintln!("invalid token: {e}"),
    }
}

Authenticate a request

let state = client.authenticate_request(raw_headers, cookies).await;

match state {
    AuthState::Authenticated(token) => {
        println!("user: {}", token.claims.sub);
        // token.claims.has_scope("openid") -> bool
        // token.claims.org_id -> Option<String>
    }
    AuthState::Unauthenticated => { /* return 401 */ }
    AuthState::Invalid(e) => { /* return 401 */ }
}

let token = client.exchange_session_token(
    "https://app.example.com/account",
    raw_cookie_header,
    Some("/v1/sessions/token"),
).await?;

Verify webhook

use xid::WebhookVerifier;

let webhook_secret =
    std::env::var("XID_WEBHOOK_SECRET").expect("XID_WEBHOOK_SECRET is required");
let verifier = WebhookVerifier::new(&webhook_secret).expect("valid secret");

match verifier.verify_from_headers(headers, body) {
    Ok(()) => {
        let payload = xid::WebhookPayload::from_bytes(body).unwrap();
        println!("event: {}", payload.event_type);
    }
    Err(e) => { /* return 400 */ }
}

Core API

Symbol Description
XidClientConfig::new(issuer) Minimal constructor. Chain builder methods for optional settings.
.with_audience(aud) Set expected audience claim.
.with_session_cookie(name) Configure an application-owned JWT cookie name; disabled by default.
.with_leeway(seconds) Clock skew tolerance for exp/nbf.
XidClient::new(config) Build client with default reqwest HTTP client.
XidClient::with_http_client(config, http) Build client with a custom reqwest client (useful for testing).
client.verify_token(token) Verify token string; returns XidResult<VerifiedToken>.
client.authenticate_request(headers, cookies) Extract and verify token from raw headers and cookies; returns AuthState.
WebhookVerifier::new(secret) Accept whsec_<base64> or raw base64 secret.
verifier.verify_from_headers(headers, body) Extract svix headers automatically and validate HMAC-SHA256 signature.

Platform notes

  • Async-first API built on tokio. Uses rustls (no OpenSSL dependency) via reqwest.
  • ES256 is the primary algorithm; RS256 is supported. PS256 support is planned. ES384/ES512 are not yet implemented.
  • Framework integration features (axum, actix-web) are planned but not included in this release.
  • XidError uses thiserror for structured error variants including JwtValidation, JwksFetch, KeyNotFound, IssuerMismatch, and webhook-specific variants.

Type to search

Use arrow keys to navigateEnter to selectEscape to close