1#![cfg(not(doctest))]
2
3use core::fmt;
4use reqwest::{Client, Url};
5use serde::{Deserialize, Serialize};
6use serde_json::Value;
7use std::{collections::HashMap, fmt::Display};
8use uuid::Uuid;
9
10#[derive(Clone)]
12pub struct AuthClient {
13 pub(crate) client: Client,
14 pub(crate) project_url: String,
17 pub(crate) api_key: String,
19 pub(crate) jwt_secret: String,
21}
22
23#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
24pub struct Session {
25 pub provider_token: Option<String>,
27 pub provider_refresh_token: Option<String>,
31 pub access_token: String,
33 pub token_type: String,
34 pub expires_in: i64,
36 pub expires_at: u64,
38 pub refresh_token: String,
40 pub user: User,
41}
42
43#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
45pub struct User {
46 pub id: Uuid,
47 pub aud: String,
48 pub role: String,
49 pub email: String,
50 #[serde(skip_serializing_if = "Option::is_none")]
51 pub invited_at: Option<String>,
52 #[serde(skip_serializing_if = "Option::is_none")]
53 pub confirmation_sent_at: Option<String>,
54 #[serde(skip_serializing_if = "Option::is_none")]
55 pub email_confirmed_at: Option<String>,
56 pub phone: String,
57 #[serde(skip_serializing_if = "Option::is_none")]
58 pub phone_confirmed_at: Option<String>,
59 #[serde(skip_serializing_if = "Option::is_none")]
60 pub confirmed_at: Option<String>,
61 #[serde(skip_serializing_if = "Option::is_none")]
62 pub recovery_sent_at: Option<String>,
63 #[serde(skip_serializing_if = "Option::is_none")]
64 pub last_sign_in_at: Option<String>,
65 pub app_metadata: AppMetadata,
66 pub user_metadata: UserMetadata,
67 pub identities: Vec<Identity>,
68 pub created_at: String,
69 pub updated_at: String,
70 pub is_anonymous: bool,
71}
72
73#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Default)]
74pub struct AppMetadata {
75 #[serde(skip_serializing_if = "Option::is_none")]
76 pub provider: Option<String>,
77 #[serde(skip_serializing_if = "Option::is_none")]
78 pub providers: Option<Vec<String>>,
79}
80
81#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Default)]
82pub struct UserMetadata {
83 #[serde(skip_serializing_if = "Option::is_none")]
84 pub name: Option<String>,
85 #[serde(skip_serializing_if = "Option::is_none")]
86 pub full_name: Option<String>,
87 #[serde(skip_serializing_if = "Option::is_none")]
88 pub email: Option<String>,
89 #[serde(skip_serializing_if = "Option::is_none")]
90 pub email_verified: Option<bool>,
91 #[serde(skip_serializing_if = "Option::is_none")]
92 pub phone_verified: Option<bool>,
93 #[serde(skip_serializing_if = "Option::is_none")]
94 pub picture: Option<String>,
95 #[serde(skip_serializing_if = "Option::is_none")]
96 pub avatar_url: Option<String>,
97 #[serde(flatten)]
98 pub custom: HashMap<String, Value>,
99}
100
101#[derive(Debug)]
102pub enum EmailSignUpResult {
103 SessionResult(Session),
104 ConfirmationResult(EmailSignUpConfirmation),
105}
106
107#[derive(Clone, Debug, Deserialize, PartialEq, Default)]
108pub struct EmailSignUpConfirmation {
109 pub id: Uuid,
110 pub aud: String,
111 pub role: String,
112 pub email: Option<String>,
113 pub phone: Option<String>,
114 pub confirmation_sent_at: String,
115 pub created_at: String,
116 pub updated_at: String,
117 pub is_anonymous: bool,
118}
119
120#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
121pub struct IdTokenCredentials {
122 pub provider: Provider,
124 #[serde(rename = "id_token")]
126 pub token: String,
127 pub access_token: Option<String>,
129 pub nonce: Option<String>,
131 pub gotrue_meta_security: Option<GotrueMetaSecurity>,
133}
134
135#[derive(Debug, Deserialize, Serialize, PartialEq, Default)]
136pub struct LoginWithOAuthOptions {
137 pub query_params: Option<HashMap<String, String>>,
138 pub redirect_to: Option<String>,
139 pub scopes: Option<String>,
140 pub skip_brower_redirect: Option<bool>,
141}
142
143#[derive(Debug, PartialEq)]
144pub struct OAuthResponse {
145 pub url: Url,
146 pub provider: Provider,
147}
148
149#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
150pub struct GotrueMetaSecurity {
151 captcha_token: Option<String>,
153}
154
155#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
156pub struct Identity {
157 pub identity_id: String,
158 pub id: String,
159 pub user_id: String,
160 pub identity_data: IdentityData,
161 pub provider: String,
162 pub last_sign_in_at: String,
163 pub created_at: String,
164 pub updated_at: String,
165 #[serde(skip_serializing_if = "Option::is_none")]
166 pub email: Option<String>,
167}
168
169#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
170pub struct IdentityData {
171 #[serde(skip_serializing_if = "Option::is_none")]
172 pub email: Option<String>,
173 pub email_verified: bool,
174 pub phone_verified: bool,
175 pub sub: String,
176}
177
178#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
179pub enum LoginOptions {
180 Email(String),
181 Phone(String),
182}
183
184#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
185pub(crate) struct LoginWithEmailAndPasswordPayload<'a> {
186 pub(crate) email: &'a str,
187 pub(crate) password: &'a str,
188}
189
190#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
191pub(crate) struct LoginWithPhoneAndPasswordPayload<'a> {
192 pub(crate) phone: &'a str,
193 pub(crate) password: &'a str,
194}
195
196#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
197pub(crate) struct SignUpWithEmailAndPasswordPayload<'a> {
198 pub(crate) email: &'a str,
199 pub(crate) password: &'a str,
200 #[serde(flatten)]
201 #[serde(skip_serializing_if = "Option::is_none")]
202 pub(crate) options: Option<SignUpWithPasswordOptions>,
203}
204
205#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
206pub(crate) struct SignUpWithPhoneAndPasswordPayload<'a> {
207 pub(crate) phone: &'a str,
208 pub(crate) password: &'a str,
209 #[serde(flatten)]
210 #[serde(skip_serializing_if = "Option::is_none")]
211 pub(crate) options: Option<SignUpWithPasswordOptions>,
212}
213
214#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
215pub(crate) struct LoginAnonymouslyPayload {
216 #[serde(flatten)]
217 #[serde(skip_serializing_if = "Option::is_none")]
218 pub(crate) options: Option<LoginAnonymouslyOptions>,
219}
220
221#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
222pub struct SignUpWithPasswordOptions {
223 #[serde(skip)]
225 pub email_redirect_to: Option<String>,
226 pub data: Option<Value>,
230 pub captcha_token: Option<String>,
232}
233
234#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
235pub struct ResetPasswordOptions {
236 #[serde(skip)]
238 pub email_redirect_to: Option<String>,
239
240 pub captcha_token: Option<String>,
242}
243
244#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
245pub struct LoginAnonymouslyOptions {
246 pub data: Option<Value>,
248 pub captcha_token: Option<String>,
250}
251
252#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
253pub(crate) struct RequestMagicLinkPayload<'a> {
254 pub(crate) email: &'a str,
255}
256
257#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
258pub struct UpdatedUser {
259 pub email: Option<String>,
260 pub password: Option<String>,
261 pub data: Option<serde_json::Value>,
262}
263
264#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
265pub(crate) struct SendSMSOtpPayload<'a> {
266 pub phone: &'a str,
267}
268
269#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
270pub struct OTPResponse {
271 #[serde(skip_serializing_if = "Option::is_none")]
272 pub message_id: Option<String>,
273}
274
275#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
276#[serde(untagged)]
277pub enum VerifyOtpParams {
278 Mobile(VerifyMobileOtpParams),
279 Email(VerifyEmailOtpParams),
280 TokenHash(VerifyTokenHashParams),
281}
282
283#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
284pub struct VerifyMobileOtpParams {
285 pub phone: String,
287 pub token: String,
289 #[serde(rename = "type")]
291 pub otp_type: OtpType,
292 #[serde(skip_serializing_if = "Option::is_none")]
294 pub options: Option<VerifyOtpOptions>,
295}
296
297#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
298pub struct VerifyEmailOtpParams {
299 pub email: String,
301 pub token: String,
303 #[serde(rename = "type")]
305 pub otp_type: OtpType,
306 #[serde(skip_serializing_if = "Option::is_none")]
308 pub options: Option<VerifyOtpOptions>,
309}
310
311#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
312pub struct VerifyTokenHashParams {
313 pub token_hash: String,
315 #[serde(rename = "type")]
317 pub otp_type: OtpType,
318}
319
320#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
321#[serde(rename_all = "snake_case")]
322pub enum OtpType {
323 #[default]
324 Signup,
325 EmailChange,
326 Sms,
327 Email,
328 PhoneChange,
329 Invite,
330 Magiclink,
331 Recovery,
332}
333
334#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
335pub struct VerifyOtpOptions {
336 #[serde(skip_serializing_if = "Option::is_none")]
338 pub redirect_to: Option<String>,
339}
340
341#[derive(Debug, Serialize, Deserialize, PartialEq, Default)]
342pub(crate) struct LoginWithEmailOtpPayload<'a> {
343 pub email: &'a str,
344 #[serde(flatten)]
345 #[serde(skip_serializing_if = "Option::is_none")]
346 pub(crate) options: Option<LoginEmailOtpParams>,
347}
348
349#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
350pub struct LoginEmailOtpParams {
351 pub captcha_token: Option<String>,
353 pub data: Option<serde_json::Value>,
355 pub email_redirect_to: Option<String>,
357 pub should_create_user: Option<bool>,
359}
360
361#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
362pub struct LoginMobileOtpParams {
363 pub captcha_token: Option<String>,
365 pub data: Option<serde_json::Value>,
367 pub channel: Option<Channel>,
369 pub should_create_user: Option<bool>,
371}
372
373#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
374pub(crate) struct RefreshSessionPayload<'a> {
375 pub refresh_token: &'a str,
376}
377
378#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
379pub(crate) struct ResetPasswordForEmailPayload {
380 pub email: String,
381 #[serde(flatten)]
382 #[serde(skip_serializing_if = "Option::is_none")]
383 pub(crate) options: Option<ResetPasswordOptions>,
384}
385
386#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
387pub struct ResendParams {
388 #[serde(rename = "type")]
389 pub otp_type: OtpType,
390 pub email: String,
391 #[serde(flatten)]
392 #[serde(skip_serializing_if = "Option::is_none")]
393 pub options: Option<DesktopResendOptions>,
394}
395
396#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
397pub struct InviteParams {
398 pub email: String,
399 pub data: Option<Value>,
400}
401
402#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
403pub struct DesktopResendOptions {
404 pub email_redirect_to: Option<String>,
405 pub captcha_token: Option<String>,
406}
407
408#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
409pub struct MobileResendParams {
410 #[serde(rename = "type")]
411 pub otp_type: OtpType,
412 pub phone: String,
413 #[serde(flatten)]
414 #[serde(skip_serializing_if = "Option::is_none")]
415 pub options: Option<MobileResendOptions>,
416}
417
418#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
419pub struct MobileResendOptions {
420 captcha_token: Option<String>,
421}
422
423#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
424#[serde(rename_all = "snake_case")]
425pub enum Channel {
426 #[default]
427 Sms,
428 Whatsapp,
429}
430
431impl Display for Channel {
432 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
433 match *self {
434 Channel::Sms => write!(f, "sms"),
435 Channel::Whatsapp => write!(f, "whatsapp"),
436 }
437 }
438}
439
440#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
442pub struct AuthServerHealth {
443 pub version: String,
445 pub name: String,
447 pub description: String,
449}
450
451#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
453pub struct AuthServerSettings {
454 pub external: External,
455 pub disable_signup: bool,
456 pub mailer_autoconfirm: bool,
457 pub phone_autoconfirm: bool,
458 pub sms_provider: String,
459 pub saml_enabled: bool,
460}
461
462#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
463pub struct External {
464 pub anonymous_users: bool,
465 pub apple: bool,
466 pub azure: bool,
467 pub bitbucket: bool,
468 pub discord: bool,
469 pub facebook: bool,
470 pub figma: bool,
471 pub fly: bool,
472 pub github: bool,
473 pub gitlab: bool,
474 pub google: bool,
475 pub keycloak: bool,
476 pub kakao: bool,
477 pub linkedin: bool,
478 pub linkedin_oidc: bool,
479 pub notion: bool,
480 pub spotify: bool,
481 pub slack: bool,
482 pub slack_oidc: bool,
483 pub workos: bool,
484 pub twitch: bool,
485 pub twitter: bool,
486 pub email: bool,
487 pub phone: bool,
488 pub zoom: bool,
489}
490
491#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
492#[serde(rename_all = "snake_case")]
493pub enum Provider {
501 Apple,
502 Azure,
503 Bitbucket,
504 Discord,
505 Facebook,
506 Figma,
507 Fly,
508 Github,
509 Gitlab,
510 Google,
511 Kakao,
512 Keycloak,
513 Linkedin,
514 LinkedinOidc,
515 Notion,
516 Slack,
517 SlackOidc,
518 Spotify,
519 Twitch,
520 Twitter,
521 Workos,
522 Zoom,
523}
524
525impl Display for Provider {
526 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> fmt::Result {
527 match *self {
528 Provider::Apple => write!(f, "apple"),
529 Provider::Azure => write!(f, "azure"),
530 Provider::Bitbucket => write!(f, "bitbucket"),
531 Provider::Discord => write!(f, "discord"),
532 Provider::Facebook => write!(f, "facebook"),
533 Provider::Figma => write!(f, "figma"),
534 Provider::Fly => write!(f, "fly"),
535 Provider::Github => write!(f, "github"),
536 Provider::Gitlab => write!(f, "gitlab"),
537 Provider::Google => write!(f, "google"),
538 Provider::Kakao => write!(f, "kakao"),
539 Provider::Keycloak => write!(f, "keycloak"),
540 Provider::Linkedin => write!(f, "linkedin"),
541 Provider::LinkedinOidc => write!(f, "linkedin_oidc"),
542 Provider::Notion => write!(f, "notion"),
543 Provider::Slack => write!(f, "slack"),
544 Provider::SlackOidc => write!(f, "slack_oidc"),
545 Provider::Spotify => write!(f, "spotify"),
546 Provider::Twitch => write!(f, "twitch"),
547 Provider::Twitter => write!(f, "twitter"),
548 Provider::Workos => write!(f, "workos"),
549 Provider::Zoom => write!(f, "zoom"),
550 }
551 }
552}
553
554#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
556#[serde(rename_all = "snake_case")]
557pub enum LogoutScope {
558 #[default]
559 Global,
560 Local,
561 Others,
562}
563
564#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
565pub struct LoginWithSSO {
566 #[serde(skip_serializing_if = "Option::is_none")]
567 pub provider_id: Option<String>,
569 #[serde(skip_serializing_if = "Option::is_none")]
570 pub domain: Option<String>,
572 #[serde(skip_serializing_if = "Option::is_none")]
573 pub options: Option<SSOLoginOptions>,
574}
575
576#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
577pub struct SSOLoginOptions {
578 #[serde(skip_serializing_if = "Option::is_none")]
579 captcha_token: Option<String>,
581 #[serde(skip_serializing_if = "Option::is_none")]
582 redirect_to: Option<String>,
584}
585
586#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
587pub struct SSOSuccess {
588 pub url: String,
594 pub status: u16,
595 pub headers: Headers,
596}
597
598#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
599pub struct Headers {
600 pub date: String,
601 #[serde(rename = "content-type")]
602 pub content_type: String,
603 #[serde(rename = "transfer-encoding")]
604 pub transfer_encoding: String,
605 pub connection: String,
606 pub server: String,
607 pub vary: String,
608 #[serde(rename = "x-okta-request-id")]
609 pub x_okta_request_id: String,
610 #[serde(rename = "x-xss-protection")]
611 pub x_xss_protection: String,
612 pub p3p: String,
613 #[serde(rename = "set-cookie")]
614 pub set_cookie: Vec<String>,
615 #[serde(rename = "content-security-policy-report-only")]
616 pub content_security_policy_report_only: String,
617 #[serde(rename = "content-security-policy")]
618 pub content_security_policy: String,
619 #[serde(rename = "x-rate-limit-limit")]
620 pub x_rate_limit_limit: String,
621 #[serde(rename = "x-rate-limit-remaining")]
622 pub x_rate_limit_remaining: String,
623 #[serde(rename = "x-rate-limit-reset")]
624 pub x_rate_limit_reset: String,
625 #[serde(rename = "referrer-policy")]
626 pub referrer_policy: String,
627 #[serde(rename = "accept-ch")]
628 pub accept_ch: String,
629 #[serde(rename = "cache-control")]
630 pub cache_control: String,
631 pub pragma: String,
632 pub expires: String,
633 #[serde(rename = "x-frame-options")]
634 pub x_frame_options: String,
635 #[serde(rename = "x-content-type-options")]
636 pub x_content_type_options: String,
637 #[serde(rename = "x-ua-compatible")]
638 pub x_ua_compatible: String,
639 #[serde(rename = "content-language")]
640 pub content_language: String,
641 #[serde(rename = "strict-transport-security")]
642 pub strict_transport_security: String,
643 #[serde(rename = "x-robots-tag")]
644 pub x_robots_tag: String,
645}
646
647impl fmt::Debug for AuthClient {
649 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
650 f.debug_struct("AuthClient")
651 .field("project_url", &self.project_url())
652 .field("api_key", &"[REDACTED]")
653 .field("jwt_secret", &"[REDACTED]")
654 .finish()
655 }
656}
657
658pub const AUTH_V1: &str = "/auth/v1";