huskarl 0.9.1

A modern OAuth2 client library.
Documentation
/*!
Huskarl provides tools for implementing secure `OAuth2` clients in rust.

This library provides several grant implementations, each driven by grant-specific
parameters that define how the grant/workflow should progress.

The library also provides a caching layer for token responses; and a HTTP authorizer
that can be used to make authenticated requests to resource servers.

## The huskarl ecosystem

This crate is one of three that fit together. Each carries its own how-to guides
and explanation in a `_docs` module:

- **`huskarl`** (this crate) — `OAuth2` **clients**: grants, token caching, and
  the request authorizer.
- [`huskarl-resource-server`](https://docs.rs/huskarl-resource-server) —
  **resource servers**: access-token validation and request authorization.
- [`huskarl-core`](https://docs.rs/huskarl-core) — the shared **foundation** the
  other two build on.

## Conformance and interoperability

Huskarl's client is verified against the official [`OpenID` conformance
suite](https://openid.net/certification/). It passes the `OpenID Connect` Core
*Basic client* certification plan, plus the **FAPI 2.0 Security Profile** and
**Message Signing** client plans — these adding `private_key_jwt` client
authentication, `DPoP` sender-constrained tokens, and signed authorization
requests (JAR). The grants are additionally run end-to-end against real
authorization servers — Keycloak, Dex, `node-oidc-provider`, and Okta — in CI.
See the [repository](https://github.com/huskarl-rs/huskarl) for the full provider
matrix and conformance plans.

## Grants

Each grant is driven by grant-specific parameters and exchanges them for a token
at the token endpoint. The simplest need only an `exchange` call; the workflow
grants add interactive steps first. Each has a [how-to guide](_docs::guide) with
setup and a worked example.

- [`ClientCredentialsGrant`](grant::client_credentials::ClientCredentialsGrant) — RFC 6749 §4.4
- [`RefreshGrant`](grant::refresh::RefreshGrant) — RFC 6749 §6
- [`AuthorizationCodeGrant`](grant::authorization_code::AuthorizationCodeGrant) — RFC 6749 §4.1
- [`DeviceAuthorizationGrant`](grant::device_authorization::DeviceAuthorizationGrant) — RFC 8628
- [`TokenExchangeGrant`](grant::token_exchange::TokenExchangeGrant) — RFC 8693
- [`JwtBearerGrant`](grant::jwt_bearer::JwtBearerGrant) — RFC 7523

Further grants — CIBA, provider-specific flows — can be implemented in this
crate or by external crates. The [`registration`] module implements OAuth 2.0
Dynamic Client Registration (RFC 7591).

## Guides and explanation

The API items in this crate are the **reference** documentation. For
task-oriented how-to guides — setting up each grant, choosing [client
authentication](_docs::guide::client_authentication), sender-constraining
tokens with [`DPoP`](_docs::guide::dpop), caching tokens, and making
authenticated requests — and design explanation (error handling, sharing a
refresh token store, refresh timing), see the [`_docs`] module.

Most applications wrap a grant in an
[`InMemoryTokenCache`](cache::InMemoryTokenCache) and an
[`HttpAuthorizer`](authorizer::HttpAuthorizer) for the request path; every
operation returns the one concrete [`Error`](core::Error) type, which embeds
in your own error enum. See [caching tokens and wiring an
authorizer](_docs::guide::caching) and [error
handling](_docs::explanation::error_handling).
*/

#![forbid(unsafe_code)]
#![deny(missing_docs)]
#![deny(rustdoc::broken_intra_doc_links)]
#![deny(clippy::unwrap_used)]
#![deny(clippy::expect_used)]
#![deny(clippy::panic)]
#![warn(clippy::pedantic)]
// bon's multiple `on(..., into)` clauses (e.g. `on(String, into), on(SecretString, into)`)
// trip this lint, which sees the repeated `into` token as a duplicated attribute.
#![allow(clippy::duplicated_attributes)]
#![cfg_attr(docsrs, feature(doc_cfg))]

mod serde_utils;

#[cfg(any(doc, docsrs))]
pub mod _docs;

pub mod authorizer;
pub mod cache;
pub mod grant;
pub mod prelude;
pub mod registration;
pub mod revocation;
pub mod token;
pub mod userinfo;

use std::sync::Arc;

#[doc(inline)]
pub use huskarl_core as core;

/// A type-erased wrapper around a [`core::crypto::verifier::JwsVerifierPlatform`] for use as a feature-gated default.
#[derive(Debug, Clone)]
pub struct DefaultJwsVerifierPlatform(Arc<dyn core::crypto::verifier::JwsVerifierPlatform>);

impl From<DefaultJwsVerifierPlatform> for Arc<dyn core::crypto::verifier::JwsVerifierPlatform> {
    fn from(value: DefaultJwsVerifierPlatform) -> Self {
        value.0
    }
}

/// The default JWS verifier platform for native platforms.
#[cfg(all(
    feature = "default-jws-verifier-platform",
    not(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none")))
))]
impl Default for DefaultJwsVerifierPlatform {
    fn default() -> Self {
        Self(Arc::new(huskarl_crypto_native::NativeVerifierPlatform))
    }
}

/// The default JWS verifier platform for WebAssembly/WebCrypto platforms.
#[cfg(all(
    feature = "default-jws-verifier-platform",
    all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none"))
))]
impl Default for DefaultJwsVerifierPlatform {
    fn default() -> Self {
        Self(Arc::new(
            huskarl_crypto_webcrypto::WebCryptoVerifierPlatform::default(),
        ))
    }
}