Skip to main content

alibi_plugins/oauth/
types.rs

1use alibi_core::wire::UserView;
2use serde::{Deserialize, Serialize};
3use validator::Validate;
4
5/// Public input to the `signInSocial` server operation.
6#[derive(Debug, Clone, Serialize, Deserialize, Validate)]
7pub struct SocialSignInRequest {
8    #[validate(length(min = 1, message = "Provider is required"))]
9    pub provider: String,
10    #[serde(rename = "callbackURL", skip_serializing_if = "Option::is_none")]
11    pub callback_url: Option<String>,
12    #[serde(rename = "newUserCallbackURL", skip_serializing_if = "Option::is_none")]
13    pub new_user_callback_url: Option<String>,
14    #[serde(rename = "errorCallbackURL", skip_serializing_if = "Option::is_none")]
15    pub error_callback_url: Option<String>,
16    #[serde(rename = "disableRedirect", skip_serializing_if = "Option::is_none")]
17    pub disable_redirect: Option<bool>,
18    #[serde(rename = "idToken", skip_serializing_if = "Option::is_none")]
19    pub id_token: Option<OAuthIdTokenRequest>,
20    #[serde(rename = "requestSignUp", skip_serializing_if = "Option::is_none")]
21    pub request_sign_up: Option<bool>,
22    #[serde(rename = "loginHint", skip_serializing_if = "Option::is_none")]
23    pub login_hint: Option<String>,
24    #[serde(
25        rename = "authorizationParams",
26        skip_serializing_if = "Option::is_none"
27    )]
28    pub authorization_params: Option<std::collections::BTreeMap<String, String>>,
29    #[serde(rename = "additionalParams", skip_serializing_if = "Option::is_none")]
30    pub additional_params: Option<std::collections::BTreeMap<String, String>>,
31    #[serde(rename = "additionalData", skip_serializing_if = "Option::is_none")]
32    #[serde(
33        default,
34        deserialize_with = "alibi_core::utils::json::deserialize_optional_map"
35    )]
36    pub additional_data: Option<serde_json::Map<String, serde_json::Value>>,
37    #[serde(skip_serializing_if = "Option::is_none")]
38    pub scopes: Option<Vec<String>>,
39}
40
41/// Public input to the `linkSocialAccount` server operation.
42#[derive(Debug, Clone, Serialize, Deserialize, Validate)]
43pub struct LinkSocialRequest {
44    #[validate(length(min = 1, message = "Provider is required"))]
45    pub provider: String,
46    #[serde(rename = "callbackURL", skip_serializing_if = "Option::is_none")]
47    pub callback_url: Option<String>,
48    #[serde(rename = "errorCallbackURL", skip_serializing_if = "Option::is_none")]
49    pub error_callback_url: Option<String>,
50    #[serde(rename = "disableRedirect", skip_serializing_if = "Option::is_none")]
51    pub disable_redirect: Option<bool>,
52    #[serde(rename = "idToken", skip_serializing_if = "Option::is_none")]
53    pub id_token: Option<OAuthIdTokenRequest>,
54    #[serde(rename = "requestSignUp", skip_serializing_if = "Option::is_none")]
55    pub request_sign_up: Option<bool>,
56    #[serde(
57        rename = "authorizationParams",
58        skip_serializing_if = "Option::is_none"
59    )]
60    pub authorization_params: Option<std::collections::BTreeMap<String, String>>,
61    #[serde(rename = "additionalParams", skip_serializing_if = "Option::is_none")]
62    pub additional_params: Option<std::collections::BTreeMap<String, String>>,
63    #[serde(rename = "additionalData", skip_serializing_if = "Option::is_none")]
64    #[serde(
65        default,
66        deserialize_with = "alibi_core::utils::json::deserialize_optional_map"
67    )]
68    pub additional_data: Option<serde_json::Map<String, serde_json::Value>>,
69    #[serde(skip_serializing_if = "Option::is_none")]
70    pub scopes: Option<Vec<String>>,
71    #[serde(rename = "loginHint", skip_serializing_if = "Option::is_none")]
72    pub login_hint: Option<String>,
73}
74
75/// ID-token credentials accepted by logical social sign-in.
76#[derive(Debug, Clone, Serialize, Deserialize, Validate)]
77pub struct OAuthIdTokenRequest {
78    #[validate(length(min = 1, message = "Token is required"))]
79    pub token: String,
80    #[serde(skip_serializing_if = "Option::is_none")]
81    pub nonce: Option<String>,
82    #[serde(skip_serializing_if = "Option::is_none")]
83    pub user: Option<super::providers::OAuthCallbackUserPayload>,
84    #[serde(rename = "accessToken", skip_serializing_if = "Option::is_none")]
85    pub access_token: Option<String>,
86    #[serde(rename = "refreshToken", skip_serializing_if = "Option::is_none")]
87    pub refresh_token: Option<String>,
88    #[serde(rename = "expiresAt", skip_serializing_if = "Option::is_none")]
89    pub expires_at: Option<i64>,
90    #[serde(skip_serializing_if = "Option::is_none")]
91    pub scopes: Option<Vec<String>>,
92}
93
94/// Provider authorization URL or authenticated user returned by social sign-in.
95#[derive(Debug, Serialize, Deserialize)]
96pub struct SocialSignInResponse {
97    #[serde(skip_serializing_if = "Option::is_none")]
98    pub url: Option<String>,
99    pub redirect: bool,
100    #[serde(skip_serializing_if = "Option::is_none")]
101    pub status: Option<bool>,
102    #[serde(skip_serializing_if = "Option::is_none")]
103    pub token: Option<String>,
104    #[serde(skip_serializing_if = "Option::is_none")]
105    pub user: Option<UserView>,
106}
107
108/// Public result of the `getAccessToken` server operation.
109#[derive(Debug, Serialize, Deserialize)]
110pub struct AccessTokenResponse {
111    #[serde(rename = "accessToken")]
112    pub access_token: Option<String>,
113    #[serde(
114        rename = "accessTokenExpiresAt",
115        skip_serializing_if = "Option::is_none"
116    )]
117    pub access_token_expires_at: Option<String>,
118    pub scopes: Vec<String>,
119    #[serde(rename = "idToken", skip_serializing_if = "Option::is_none")]
120    pub id_token: Option<String>,
121}
122
123impl From<super::OAuthTokenSet> for AccessTokenResponse {
124    fn from(tokens: super::OAuthTokenSet) -> Self {
125        Self {
126            access_token: tokens.access_token,
127            access_token_expires_at: tokens
128                .access_token_expires_at
129                .map(|value| value.to_rfc3339_opts(chrono::SecondsFormat::Millis, true)),
130            scopes: tokens.scopes,
131            id_token: tokens.id_token,
132        }
133    }
134}
135
136#[derive(Debug, Serialize)]
137pub(super) struct RefreshTokenResponse {
138    #[serde(rename = "accessToken")]
139    pub access_token: Option<String>,
140    #[serde(rename = "accessTokenExpiresAt")]
141    pub access_token_expires_at: Option<String>,
142    #[serde(rename = "refreshToken")]
143    pub refresh_token: Option<String>,
144    #[serde(rename = "refreshTokenExpiresAt")]
145    pub refresh_token_expires_at: Option<String>,
146    pub scope: Option<String>,
147    #[serde(rename = "idToken")]
148    pub id_token: Option<String>,
149    #[serde(rename = "providerId")]
150    pub provider_id: String,
151    #[serde(rename = "accountId", skip_serializing_if = "Option::is_none")]
152    pub account_id: Option<String>,
153}
154
155/// Owned account identity returned by the `accountInfo` server operation.
156#[derive(Debug, Serialize, Deserialize)]
157#[serde(rename_all = "camelCase")]
158pub struct AccountInfoAccount {
159    #[serde(skip_serializing_if = "Option::is_none")]
160    pub id: Option<String>,
161    pub provider_id: String,
162    pub account_id: String,
163}
164
165/// Provider profile and owned account returned by the `accountInfo` server operation.
166#[derive(Debug, Serialize, Deserialize)]
167pub struct AccountInfoResponse {
168    pub user: alibi_core::field_policy::FieldOutput,
169    pub data: serde_json::Value,
170    pub account: AccountInfoAccount,
171}
172
173impl SocialSignInRequest {
174    /// Construct provider selection; optional OAuth inputs remain configurable.
175    #[must_use]
176    pub fn new(provider: impl Into<String>) -> Self {
177        Self {
178            provider: provider.into(),
179            callback_url: None,
180            new_user_callback_url: None,
181            error_callback_url: None,
182            disable_redirect: None,
183            id_token: None,
184            request_sign_up: None,
185            login_hint: None,
186            authorization_params: None,
187            additional_params: None,
188            additional_data: None,
189            scopes: None,
190        }
191    }
192}
193
194impl LinkSocialRequest {
195    /// Construct provider selection; the caller supplies verified session headers at dispatch.
196    #[must_use]
197    pub fn new(provider: impl Into<String>) -> Self {
198        Self {
199            provider: provider.into(),
200            callback_url: None,
201            error_callback_url: None,
202            disable_redirect: None,
203            id_token: None,
204            request_sign_up: None,
205            authorization_params: None,
206            additional_params: None,
207            additional_data: None,
208            scopes: None,
209            login_hint: None,
210        }
211    }
212}
213
214/// Validated input shared by the OAuth callback's logical query and POST body.
215#[derive(Debug, Clone, Default, Serialize, Deserialize)]
216pub struct OAuthCallbackInput {
217    #[serde(skip_serializing_if = "Option::is_none")]
218    pub code: Option<String>,
219    #[serde(skip_serializing_if = "Option::is_none")]
220    pub error: Option<String>,
221    #[serde(skip_serializing_if = "Option::is_none")]
222    pub device_id: Option<String>,
223    #[serde(skip_serializing_if = "Option::is_none")]
224    pub error_description: Option<String>,
225    #[serde(skip_serializing_if = "Option::is_none")]
226    pub state: Option<String>,
227    #[serde(skip_serializing_if = "Option::is_none")]
228    pub user: Option<String>,
229    #[serde(skip_serializing_if = "Option::is_none")]
230    pub iss: Option<String>,
231}