A better Rust ATProto crate
1mod client_metadata;
2mod metadata;
3mod request;
4mod response;
5mod token;
6
7use crate::scopes::Scope;
8
9pub use self::client_metadata::*;
10pub use self::metadata::*;
11pub use self::request::*;
12pub use self::response::*;
13pub use self::token::*;
14use jacquard_common::CowStr;
15use jacquard_common::IntoStatic;
16use jacquard_common::deps::fluent_uri::Uri;
17use serde::Deserialize;
18
19/// The `prompt` parameter for an OAuth authorization request.
20///
21/// Controls whether the authorization server prompts the user for
22/// re-authentication or re-consent, as defined in OpenID Connect Core §3.1.2.1.
23#[derive(Debug, Deserialize, Clone, Copy)]
24pub enum AuthorizeOptionPrompt {
25 /// Prompt the user to re-authenticate.
26 Login,
27 /// Do not display any authentication or consent UI; fail if interaction is required.
28 None,
29 /// Prompt the user for explicit consent before issuing tokens.
30 Consent,
31 /// Prompt the user to select an account when multiple sessions are active.
32 SelectAccount,
33}
34
35impl From<AuthorizeOptionPrompt> for CowStr<'static> {
36 fn from(value: AuthorizeOptionPrompt) -> Self {
37 match value {
38 AuthorizeOptionPrompt::Login => CowStr::new_static("login"),
39 AuthorizeOptionPrompt::None => CowStr::new_static("none"),
40 AuthorizeOptionPrompt::Consent => CowStr::new_static("consent"),
41 AuthorizeOptionPrompt::SelectAccount => CowStr::new_static("select_account"),
42 }
43 }
44}
45
46/// Options for initiating an OAuth authorization request.
47#[derive(Debug)]
48pub struct AuthorizeOptions<'s> {
49 /// Override the redirect URI registered in the client metadata.
50 pub redirect_uri: Option<Uri<String>>,
51 /// Scopes to request. Defaults to an empty list (server-defined defaults apply).
52 pub scopes: Vec<Scope<'s>>,
53 /// Optional prompt hint for the authorization server's UI.
54 pub prompt: Option<AuthorizeOptionPrompt>,
55 /// Opaque client-provided state value, echoed back in the callback for CSRF protection.
56 pub state: Option<CowStr<'s>>,
57}
58
59impl Default for AuthorizeOptions<'_> {
60 fn default() -> Self {
61 Self {
62 redirect_uri: None,
63 scopes: vec![],
64 prompt: None,
65 state: None,
66 }
67 }
68}
69
70impl<'s> AuthorizeOptions<'s> {
71 /// Set the `prompt` parameter sent to the authorization server.
72 pub fn with_prompt(mut self, prompt: AuthorizeOptionPrompt) -> Self {
73 self.prompt = Some(prompt);
74 self
75 }
76
77 /// Set a CSRF-protection `state` value to be echoed in the callback.
78 pub fn with_state(mut self, state: CowStr<'s>) -> Self {
79 self.state = Some(state);
80 self
81 }
82
83 /// Override the redirect URI for this specific authorization request.
84 pub fn with_redirect_uri(mut self, redirect_uri: Uri<String>) -> Self {
85 self.redirect_uri = Some(redirect_uri);
86 self
87 }
88
89 /// Set the OAuth scopes to request.
90 pub fn with_scopes(mut self, scopes: Vec<Scope<'s>>) -> Self {
91 self.scopes = scopes;
92 self
93 }
94}
95
96/// Query parameters delivered to the OAuth redirect URI after user authorization.
97#[derive(Debug, Deserialize)]
98pub struct CallbackParams<'s> {
99 /// The authorization code issued by the authorization server.
100 #[serde(borrow)]
101 pub code: CowStr<'s>,
102 /// The `state` value originally sent in the authorization request, used to
103 /// verify the response belongs to this session.
104 pub state: Option<CowStr<'s>>,
105 /// The `iss` (issuer) parameter, required by RFC 9207 to prevent mix-up attacks.
106 pub iss: Option<CowStr<'s>>,
107}
108
109impl IntoStatic for CallbackParams<'_> {
110 type Output = CallbackParams<'static>;
111
112 fn into_static(self) -> Self::Output {
113 CallbackParams {
114 code: self.code.into_static(),
115 state: self.state.map(|s| s.into_static()),
116 iss: self.iss.map(|s| s.into_static()),
117 }
118 }
119}