atrium_oauth/
lib.rs

1#![doc = include_str!("../README.md")]
2mod atproto;
3mod constants;
4mod error;
5mod http_client;
6mod jose;
7mod keyset;
8mod oauth_client;
9mod oauth_session;
10mod resolver;
11mod server_agent;
12pub mod store;
13mod types;
14mod utils;
15
16pub use atproto::{
17    AtprotoClientMetadata, AtprotoLocalhostClientMetadata, AuthMethod, GrantType, KnownScope, Scope,
18};
19pub use error::{Error, Result};
20#[cfg(feature = "default-client")]
21pub use http_client::default::DefaultHttpClient;
22pub use http_client::dpop::DpopClient;
23pub use oauth_client::{OAuthClient, OAuthClientConfig};
24pub use oauth_session::OAuthSession;
25pub use resolver::OAuthResolverConfig;
26pub use types::{
27    AuthorizeOptionPrompt, AuthorizeOptions, CallbackParams, OAuthClientMetadata, TokenSet,
28};
29
30#[cfg(test)]
31mod tests {
32    use crate::{
33        resolver::OAuthResolver,
34        types::{
35            OAuthAuthorizationServerMetadata, OAuthClientMetadata, OAuthProtectedResourceMetadata,
36            TryIntoOAuthClientMetadata,
37        },
38        AtprotoLocalhostClientMetadata, OAuthResolverConfig,
39    };
40    use atrium_api::{
41        did_doc::{DidDocument, Service},
42        types::string::{Did, Handle},
43    };
44    use atrium_common::resolver::Resolver;
45    use atrium_xrpc::HttpClient;
46    use jose_jwk::Key;
47    use std::sync::Arc;
48
49    pub struct MockDidResolver;
50
51    impl Resolver for MockDidResolver {
52        type Input = Did;
53        type Output = DidDocument;
54        type Error = atrium_identity::Error;
55        async fn resolve(&self, did: &Self::Input) -> Result<Self::Output, Self::Error> {
56            Ok(DidDocument {
57                context: None,
58                id: did.as_ref().to_string(),
59                also_known_as: None,
60                verification_method: None,
61                service: Some(vec![Service {
62                    id: String::from("#atproto_pds"),
63                    r#type: String::from("AtprotoPersonalDataServer"),
64                    service_endpoint: String::from("https://aud.example.com"),
65                }]),
66            })
67        }
68    }
69
70    pub struct NoopHandleResolver;
71
72    impl Resolver for NoopHandleResolver {
73        type Input = Handle;
74        type Output = Did;
75        type Error = atrium_identity::Error;
76        async fn resolve(&self, _: &Self::Input) -> Result<Self::Output, Self::Error> {
77            unimplemented!()
78        }
79    }
80
81    pub fn oauth_resolver<T>(
82        http_client: Arc<T>,
83    ) -> OAuthResolver<T, MockDidResolver, NoopHandleResolver>
84    where
85        T: HttpClient + Send + Sync,
86    {
87        OAuthResolver::new(
88            OAuthResolverConfig {
89                did_resolver: MockDidResolver,
90                handle_resolver: NoopHandleResolver,
91                authorization_server_metadata: Default::default(),
92                protected_resource_metadata: Default::default(),
93            },
94            http_client,
95        )
96    }
97
98    pub fn dpop_key() -> Key {
99        serde_json::from_str(
100            r#"{
101                "kty": "EC",
102                "crv": "P-256",
103                "x": "NIRNgPVAwnVNzN5g2Ik2IMghWcjnBOGo9B-lKXSSXFs",
104                "y": "iWF-Of43XoSTZxcadO9KWdPTjiCoviSztYw7aMtZZMc",
105                "d": "9MuCYfKK4hf95p_VRj6cxKJwORTgvEU3vynfmSgFH2M"
106            }"#,
107        )
108        .expect("key should be valid")
109    }
110
111    pub fn server_metadata() -> OAuthAuthorizationServerMetadata {
112        OAuthAuthorizationServerMetadata {
113            issuer: String::from("https://iss.example.com"),
114            token_endpoint: String::from("https://iss.example.com/token"),
115            token_endpoint_auth_methods_supported: Some(vec![
116                String::from("none"),
117                String::from("private_key_jwt"),
118            ]),
119            ..Default::default()
120        }
121    }
122
123    pub fn client_metadata() -> OAuthClientMetadata {
124        AtprotoLocalhostClientMetadata::default()
125            .try_into_client_metadata(&None)
126            .expect("client metadata should be valid")
127    }
128
129    pub fn protected_resource_metadata() -> OAuthProtectedResourceMetadata {
130        OAuthProtectedResourceMetadata {
131            resource: String::from("https://aud.example.com"),
132            authorization_servers: Some(vec![String::from("https://iss.example.com")]),
133            ..Default::default()
134        }
135    }
136}