An open API service indexing awesome lists of open source software.

https://github.com/workos/workos-rust

Official Rust SDK for interacting with the WorkOS API
https://github.com/workos/workos-rust

backend sdk

Last synced: 2 days ago
JSON representation

Official Rust SDK for interacting with the WorkOS API

Awesome Lists containing this project

README

          

# WorkOS Rust Library

The WorkOS Rust SDK provides async access to the WorkOS API from Rust applications. It uses `tokio`, ships with a default `reqwest` HTTP transport, and includes helpers for common WorkOS flows such as AuthKit, SSO, webhooks, sessions, JWKS, PKCE, and Vault local crypto.

## Documentation

- [WorkOS API Reference](https://workos.com/docs/reference)
- [Crate docs on docs.rs](https://docs.rs/workos)
- [Changelog](./CHANGELOG.md)

## Installation

Requires Rust `1.88+` (edition 2024). The repository pins this via `rust-toolchain.toml`, so a fresh checkout will install the matching toolchain automatically when you run any `cargo` or `./script/ci` command under `rustup`.

```bash
cargo add workos
```

By default, the crate enables `reqwest` with `rustls-tls`. You can switch TLS backends or provide a custom HTTP transport; see [HTTP Transport](#http-transport).

## Quick Start

```rust
use workos::{Client, organizations::ListOrganizationsParams};

#[tokio::main]
async fn main() -> Result<(), workos::Error> {
let client = Client::builder()
.api_key(std::env::var("WORKOS_API_KEY").unwrap())
.client_id(std::env::var("WORKOS_CLIENT_ID").unwrap())
.build();

let page = client
.organizations()
.list_organizations(ListOrganizationsParams::default())
.await?;

for org in page.data {
println!("{}: {}", org.id, org.name);
}

Ok(())
}
```

For an API-key-only client with default settings:

```rust
let client = workos::Client::new(std::env::var("WORKOS_API_KEY").unwrap());
```

## Configuration

`Client::builder()` supports:

| Method | Description |
| ----------------- | ------------------------------------------------------------------- |
| `.api_key(_)` | WorkOS secret key (`sk_...`), required for authenticated API calls. |
| `.client_id(_)` | WorkOS Client ID, required for AuthKit, SSO, and JWKS helpers. |
| `.base_url(_)` | Override the API host. Defaults to `https://api.workos.com`. |
| `.timeout(_)` | Per-request timeout. Defaults to 30 seconds. |
| `.max_retries(_)` | Retry budget for `429` and `5xx` responses. Defaults to 3. |
| `.user_agent(_)` | Override the `User-Agent` header. |
| `.transport(_)` | Plug in a custom `HttpTransport`. |

`build()` panics if the supplied API key or user-agent contains bytes that aren't valid in an HTTP header. Use `.try_build()` to surface those failures as `Err(workos::Error::Builder(_))` instead — useful when the API key comes from untrusted input.

The client is cheap to clone and can be shared across handlers and tasks.

## API Access

API resources are exposed as accessors on `Client`, for example:

```rust
client.organizations();
client.user_management();
client.sso();
client.webhooks();
client.audit_logs();
```

List endpoints return `Page` values with `data` and `list_metadata` cursors. The crate also exports `auto_paginate` for stream-based iteration.

Every API call returns `Result<_, workos::Error>`. The error type includes API errors, transport failures, decode errors, configuration errors, and helper-specific failures. It also provides predicates such as `is_unauthorized()`, `is_not_found()`, `is_rate_limited()`, and `is_server_error()`.

See the [crate docs](https://docs.rs/workos) for the full resource list, request and response types, pagination details, and helper APIs.

### Forward-compatible enums

Generated enums are `#[non_exhaustive]` and include an `Unknown(String)` variant for wire values the SDK doesn't recognize yet — WorkOS can add new enum values server-side without breaking deserialization for older SDK builds. Match defensively:

```rust
use workos::ConnectionType;

match connection.r#type {
ConnectionType::GoogleOAuth => { /* ... */ }
ConnectionType::Unknown(raw) => {
log::warn!("unknown connection type: {raw}");
}
_ => { /* ... */ }
}
```

The original wire string is preserved through round-trips: serializing an `Unknown("FooBar")` re-emits `"FooBar"` verbatim. Each enum also implements `Display`, `FromStr` (infallible), and `AsRef` for ergonomic conversions.

## Per-Request Options

Each generated method has a `*_with_options` companion that takes a `RequestOptions`. Use it to pass an idempotency key, additional headers, or a per-request retry policy:

```rust
use workos::{RequestOptions, organizations::CreateOrganizationParams};

let opts = RequestOptions::new().idempotency_key("ik_create_acme_42");

let org = client
.organizations()
.create_organization_with_options(
CreateOrganizationParams::new(workos::OrganizationInput {
name: "Acme".into(),
..Default::default()
}),
Some(&opts),
)
.await?;
```

Replaying a mutating request with the same idempotency key is safe; WorkOS recognises the key on the server side.

### Request strategies

For finer-grained control, attach a `RequestStrategy` to override the client's default retry behavior on a single call:

```rust
use workos::{RequestOptions, RequestStrategy};

// Send exactly once, regardless of `max_retries`:
let opts = RequestOptions::new().strategy(RequestStrategy::Once);

// Make a mutation idempotent and retry-eligible (the key is also sent
// as the `Idempotency-Key` header):
let opts = RequestOptions::new()
.strategy(RequestStrategy::Idempotent("ik_42".into()));

// Custom retry budget with jitter:
let opts = RequestOptions::new().strategy(RequestStrategy::ExponentialBackoff {
max_attempts: 5,
jitter: true,
});
```

Variants: `Once`, `Idempotent(key)`, `Retry { max_attempts }`, `ExponentialBackoff { max_attempts, jitter }`.

## Errors

API errors carry structured metadata. Always log `request_id()` when reporting bugs to WorkOS:

```rust
match client.organizations().get_organization("org_missing").await {
Ok(org) => println!("{org:?}"),
Err(err) if err.is_not_found() => println!("not found"),
Err(err) => {
eprintln!(
"API error {} (code={:?}, request_id={:?}): {}",
err.status().unwrap_or(0),
err.code(),
err.request_id(),
err.api().map(|a| a.message.as_str()).unwrap_or(""),
);
if let Some(after) = err.retry_after() {
eprintln!("retry after {after:?}");
}
}
}
```

`err.api()` returns the full `ApiError` with the raw response headers and body for advanced debugging.

## Sensitive Fields

Fields that hold credentials or tokens — `password`, `client_secret`, `access_token`, `refresh_token`, `token`, `secret`, etc. — are typed as `workos::SecretString`. Their `Debug` representation prints `""`, so secrets don't leak through logs, panic messages, or error reports. Read the underlying value with `.expose()` when you genuinely need it:

```rust
let token: &str = session.access_token.expose();
```

`SecretString` serializes transparently as a JSON string, so the wire format is unchanged. Constructors that accept a sensitive parameter take `impl Into` — passing a `String` or `&str` works without an explicit conversion.

## Retries

The client retries `429` and `5xx` responses (plus retryable transport errors) up to `max_retries` times — default `3` — with exponential backoff and equal-jitter. The `Retry-After` header is honored when present and supersedes the computed backoff.

To preserve at-most-once semantics for state-changing calls, only safe HTTP methods (`GET`/`HEAD`/`OPTIONS`) and requests carrying an `Idempotency-Key` are auto-retried. POST/PUT/PATCH/DELETE without an idempotency key are sent exactly once.

```rust
// Disable retries entirely for this client:
let client = workos::Client::builder()
.api_key(std::env::var("WORKOS_API_KEY").unwrap())
.max_retries(0)
.build();
```

Pair mutations with an idempotency key (or `RequestStrategy::Idempotent`) so a redelivered request is processed exactly once on the server.

## Auto-Paging

Every list endpoint generates a `*_auto_paging` companion that returns a `futures_util::Stream`, advancing the `after` cursor under the hood:

```rust
use futures_util::TryStreamExt;
use workos::organizations::ListOrganizationsParams;

let all: Vec = client
.organizations()
.list_organizations_auto_paging(ListOrganizationsParams::default())
.try_collect()
.await?;
```

For custom paginated flows the crate also re-exports the lower-level `auto_paginate(fetch)` helper, which drives any `(after) -> Result, _>` closure to exhaustion.

## Helpers

The SDK includes hand-maintained helpers for:

- AuthKit and SSO URL builders, PKCE flows, token exchange, logout, and device authorization.
- Webhook signature verification.
- Sealed session cookies.
- JWKS fetching and URL construction.
- Vault key-value operations and optional local AES-GCM encryption.
- Public PKCE-only clients for browser or mobile flows that must not hold an API key.

## HTTP Transport

The default HTTP transport is `reqwest`, gated behind the default `reqwest` feature. To use another client, share an existing request pipeline, or support environments such as WASM, disable default features and provide a `workos::transport::HttpTransport` implementation:

```toml
# Cargo.toml
workos = { version = "1", default-features = false }
```

```rust
let transport: workos::transport::SharedTransport = std::sync::Arc::new(MyTransport);

let client = workos::Client::builder()
.api_key("sk_...")
.transport(transport)
.build();
```

Supported crate features:

| Feature | Default | Description |
| ------------ | ------- | ----------------------------------------------------- |
| `reqwest` | yes | Enables the bundled `reqwest` transport. |
| `rustls-tls` | yes | Uses `rustls` for TLS through `reqwest`. |
| `native-tls` | no | Uses the platform native TLS stack through `reqwest`. |

## More Information

- [WorkOS Docs](https://workos.com/docs)
- [API Reference](https://workos.com/docs/reference)
- [Issues](https://github.com/workos/workos-rust/issues)

## License

MIT. See [LICENSE.txt](./LICENSE.txt).