A library for ATProtocol identities.
1//! Axum state management for OAuth configuration.
2//!
3//! Request extractors and HTTP client wrappers for OAuth
4//! client configuration injection in handlers.
5
6use atproto_identity::key::KeyData;
7use axum::extract::{FromRef, FromRequestParts};
8use http::request::Parts;
9use std::convert::Infallible;
10
11#[cfg(feature = "zeroize")]
12use zeroize::{Zeroize, ZeroizeOnDrop};
13
14/// OAuth client configuration for Axum handlers.
15///
16/// Contains the essential configuration needed for OAuth client operations.
17#[derive(Clone, Default)]
18#[cfg_attr(feature = "zeroize", derive(Zeroize, ZeroizeOnDrop))]
19pub struct OAuthClientConfig {
20 /// OAuth client identifier
21 #[cfg_attr(feature = "zeroize", zeroize(skip))]
22 pub client_id: String,
23
24 /// Allowed OAuth redirect URIs
25 #[cfg_attr(feature = "zeroize", zeroize(skip))]
26 pub redirect_uris: String,
27
28 /// JSON Web Key Set URI for public keys
29 #[cfg_attr(feature = "zeroize", zeroize(skip))]
30 pub jwks_uri: Option<String>,
31
32 /// Signing keys for JWT operations
33 pub signing_keys: Vec<KeyData>,
34
35 /// OAuth scope, defaults to "atproto transition:generic"
36 #[cfg_attr(feature = "zeroize", zeroize(skip))]
37 pub scope: Option<String>,
38
39 /// Optional human-readable client name
40 #[cfg_attr(feature = "zeroize", zeroize(skip))]
41 pub client_name: Option<String>,
42
43 /// Optional client website URI
44 #[cfg_attr(feature = "zeroize", zeroize(skip))]
45 pub client_uri: Option<String>,
46
47 /// Optional client logo URI
48 #[cfg_attr(feature = "zeroize", zeroize(skip))]
49 pub logo_uri: Option<String>,
50
51 /// Optional terms of service URI
52 #[cfg_attr(feature = "zeroize", zeroize(skip))]
53 pub tos_uri: Option<String>,
54
55 /// Optional privacy policy URI
56 #[cfg_attr(feature = "zeroize", zeroize(skip))]
57 pub policy_uri: Option<String>,
58}
59
60impl OAuthClientConfig {
61 /// Returns the OAuth scope, using the default "atproto transition:generic" if not set.
62 pub fn scope(&self) -> &str {
63 self.scope
64 .as_deref()
65 .unwrap_or("atproto transition:generic")
66 }
67}
68
69impl<S> FromRequestParts<S> for OAuthClientConfig
70where
71 OAuthClientConfig: FromRef<S>,
72 S: Send + Sync,
73{
74 type Rejection = Infallible;
75
76 /// Extracts OAuth client configuration from Axum application state.
77 async fn from_request_parts(_parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {
78 let oauth_client_config = OAuthClientConfig::from_ref(state);
79 Ok(oauth_client_config)
80 }
81}
82
83/// HTTP client wrapper for dependency injection.
84///
85/// Wraps a reqwest::Client for use in Axum extractors.
86#[derive(Clone)]
87pub struct HttpClient(pub reqwest::Client);
88
89impl std::ops::Deref for HttpClient {
90 type Target = reqwest::Client;
91
92 /// Provides direct access to the underlying reqwest::Client.
93 fn deref(&self) -> &Self::Target {
94 &self.0
95 }
96}
97
98impl<S> FromRequestParts<S> for HttpClient
99where
100 reqwest::Client: FromRef<S>,
101 S: Send + Sync,
102{
103 type Rejection = Infallible;
104
105 /// Extracts HTTP client from Axum application state.
106 async fn from_request_parts(_parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {
107 let client = reqwest::Client::from_ref(state);
108 Ok(HttpClient(client))
109 }
110}