Skip to main content

kynos_openapi/model/security/
oauth.rs

1//! The OAuth Flows and OAuth Flow Objects.
2
3use serde::{Deserialize, Serialize};
4
5use crate::{Map, model::extensions::Extensions};
6
7/// The OAuth 2.0 flows a scheme supports.
8#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
9pub struct OAuthFlows {
10    /// The implicit flow.
11    #[serde(default, skip_serializing_if = "Option::is_none")]
12    pub implicit: Option<OAuthFlow>,
13
14    /// The resource owner password credentials flow.
15    #[serde(default, skip_serializing_if = "Option::is_none")]
16    pub password: Option<OAuthFlow>,
17
18    /// The client credentials flow.
19    #[serde(
20        rename = "clientCredentials",
21        default,
22        skip_serializing_if = "Option::is_none"
23    )]
24    pub client_credentials: Option<OAuthFlow>,
25
26    /// The authorization code flow.
27    #[serde(
28        rename = "authorizationCode",
29        default,
30        skip_serializing_if = "Option::is_none"
31    )]
32    pub authorization_code: Option<OAuthFlow>,
33
34    /// The RFC 8628 device authorization flow.
35    ///
36    /// Introduced in OpenAPI 3.2.
37    #[cfg(feature = "openapi32")]
38    #[serde(
39        rename = "deviceAuthorization",
40        default,
41        skip_serializing_if = "Option::is_none"
42    )]
43    pub device_authorization: Option<OAuthFlow>,
44
45    /// Specification extensions.
46    #[serde(flatten)]
47    pub extensions: Extensions,
48}
49
50impl OAuthFlows {
51    /// Adds the implicit flow.
52    #[must_use]
53    pub fn with_implicit(mut self, flow: OAuthFlow) -> Self {
54        self.implicit = Some(flow);
55        self
56    }
57
58    /// Adds the resource owner password credentials flow.
59    #[must_use]
60    pub fn with_password(mut self, flow: OAuthFlow) -> Self {
61        self.password = Some(flow);
62        self
63    }
64
65    /// Adds the client credentials flow.
66    #[must_use]
67    pub fn with_client_credentials(mut self, flow: OAuthFlow) -> Self {
68        self.client_credentials = Some(flow);
69        self
70    }
71
72    /// Adds the authorization code flow.
73    #[must_use]
74    pub fn with_authorization_code(mut self, flow: OAuthFlow) -> Self {
75        self.authorization_code = Some(flow);
76        self
77    }
78
79    /// Adds the RFC 8628 device authorization flow.
80    #[cfg(feature = "openapi32")]
81    #[must_use]
82    pub fn with_device_authorization(mut self, flow: OAuthFlow) -> Self {
83        self.device_authorization = Some(flow);
84        self
85    }
86}
87
88/// The configuration of one OAuth 2.0 flow.
89///
90/// Which URL fields are required depends on the flow this is attached to. That
91/// pairing is *not* checked here, and the model is deliberately the permissive
92/// half: a flow read back from someone else's description has to round-trip
93/// whatever it said. `#[derive(SecurityScheme)]` enforces the pairing where the
94/// flow is written, which is the layer that knows which flow it is naming.
95#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
96pub struct OAuthFlow {
97    /// The authorization URL. Required for the implicit and authorization code
98    /// flows.
99    #[serde(
100        rename = "authorizationUrl",
101        default,
102        skip_serializing_if = "Option::is_none"
103    )]
104    pub authorization_url: Option<String>,
105
106    /// The token URL. Required for the password, client credentials and
107    /// authorization code flows.
108    #[serde(rename = "tokenUrl", default, skip_serializing_if = "Option::is_none")]
109    pub token_url: Option<String>,
110
111    /// The device authorization URL. Required for the device authorization
112    /// flow.
113    ///
114    /// Introduced in OpenAPI 3.2.
115    #[cfg(feature = "openapi32")]
116    #[serde(
117        rename = "deviceAuthorizationUrl",
118        default,
119        skip_serializing_if = "Option::is_none"
120    )]
121    pub device_authorization_url: Option<String>,
122
123    /// The URL used to obtain refresh tokens.
124    #[serde(
125        rename = "refreshUrl",
126        default,
127        skip_serializing_if = "Option::is_none"
128    )]
129    pub refresh_url: Option<String>,
130
131    /// The scopes available, mapped to a short description of each.
132    ///
133    /// Required, though it may be empty.
134    pub scopes: Map<String>,
135
136    /// Specification extensions.
137    #[serde(flatten)]
138    pub extensions: Extensions,
139}
140
141impl OAuthFlow {
142    /// Creates a flow with the given scopes and no URLs.
143    pub fn new(scopes: impl IntoIterator<Item = (String, String)>) -> Self {
144        Self {
145            scopes: scopes.into_iter().collect(),
146            ..Self::default()
147        }
148    }
149
150    /// Sets the authorization URL.
151    #[must_use]
152    pub fn with_authorization_url(mut self, url: impl Into<String>) -> Self {
153        self.authorization_url = Some(url.into());
154        self
155    }
156
157    /// Sets the token URL.
158    #[must_use]
159    pub fn with_token_url(mut self, url: impl Into<String>) -> Self {
160        self.token_url = Some(url.into());
161        self
162    }
163
164    /// Sets the refresh URL.
165    #[must_use]
166    pub fn with_refresh_url(mut self, url: impl Into<String>) -> Self {
167        self.refresh_url = Some(url.into());
168        self
169    }
170
171    /// Sets the device authorization URL.
172    ///
173    /// Required for the device authorization flow, and legal on any of them.
174    #[cfg(feature = "openapi32")]
175    #[must_use]
176    pub fn with_device_authorization_url(mut self, url: impl Into<String>) -> Self {
177        self.device_authorization_url = Some(url.into());
178        self
179    }
180}