dioxus_clerk/hooks.rs
1//! Reactive accessors for descendants of `ClerkProvider`.
2
3use crate::context::{ClerkContext, use_clerk_context};
4use crate::core::{AuthRequirement, AuthState, AuthStatus, ClerkError, Session, User};
5use dioxus::prelude::*;
6
7fn auth_state_signal(
8 ctx: ClerkContext,
9 treat_pending_as_signed_out: bool,
10) -> ReadSignal<AuthState> {
11 // `treat_pending_as_signed_out` is a plain value, not a signal, so track it
12 // with `use_reactive`; otherwise a caller passing a changing flag would
13 // keep reading the first render's value.
14 use_memo(use_reactive(
15 &treat_pending_as_signed_out,
16 move |treat_pending_as_signed_out| {
17 ctx.auth
18 .read()
19 .resolve_pending(treat_pending_as_signed_out)
20 .to_state()
21 },
22 ))
23 .into()
24}
25
26/// Reactive auth hook result returned by [`use_auth`].
27#[derive(Clone, Copy)]
28pub struct UseAuth {
29 inner: ReadSignal<AuthState>,
30 ctx: ClerkContext,
31}
32
33impl std::fmt::Debug for UseAuth {
34 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
35 f.debug_struct("UseAuth")
36 .field("state", &*self.inner.peek())
37 .finish_non_exhaustive()
38 }
39}
40
41impl UseAuth {
42 /// Return the current app-visible auth state.
43 pub fn state(&self) -> AuthState {
44 self.inner.read().clone()
45 }
46
47 /// Return the underlying read-only Dioxus signal for advanced composition.
48 pub fn signal(&self) -> ReadSignal<AuthState> {
49 self.inner
50 }
51
52 /// Return the explicit auth resolution status.
53 pub fn status(&self) -> AuthStatus {
54 self.inner.read().status
55 }
56
57 /// True while auth has not resolved to signed-in or signed-out yet.
58 pub fn is_loading(&self) -> bool {
59 self.status().is_loading()
60 }
61
62 /// True only when auth has resolved and no active session is known.
63 pub fn is_signed_out(&self) -> bool {
64 self.status().is_signed_out()
65 }
66
67 /// Whether clerk-js has finished loading on the client.
68 pub fn is_loaded(&self) -> bool {
69 self.inner.read().is_loaded
70 }
71
72 /// Whether a session is active.
73 pub fn is_signed_in(&self) -> bool {
74 self.inner.read().is_signed_in()
75 }
76
77 /// Clerk user id, if signed in.
78 pub fn user_id(&self) -> Option<String> {
79 self.inner.read().user_id.clone()
80 }
81
82 /// Return the user id, or an error when auth is not signed in.
83 ///
84 /// Returns [`ClerkError::NotLoaded`] while auth is still resolving and
85 /// [`ClerkError::Unauthenticated`] once it has resolved without a
86 /// signed-in user, so callers can wait out the former and redirect on the
87 /// latter without flashing sign-in UI at a signed-in user.
88 pub fn require_signed_in(&self) -> Result<String, ClerkError> {
89 self.inner.read().require_signed_in().map(ToOwned::to_owned)
90 }
91
92 /// Get the active session token from clerk-js.
93 ///
94 /// This mirrors Clerk React's `useAuth().getToken()` convenience. The call
95 /// waits for the browser Clerk lifecycle to load before reading clerk-js.
96 ///
97 /// Returns `Err(`[`ClerkError::Offline`]`)` when the browser is offline
98 /// (clerk-js 6 throws `ClerkOfflineError` here), a transient condition
99 /// callers can retry rather than treat as signed-out.
100 pub async fn get_token(&self) -> Result<Option<String>, ClerkError> {
101 self.get_token_with_options(serde_json::Value::Null).await
102 }
103
104 /// Get the active session token with Clerk `getToken(...)` options.
105 pub async fn get_token_with_options(
106 &self,
107 options: impl Into<serde_json::Value>,
108 ) -> Result<Option<String>, ClerkError> {
109 ClerkActions { ctx: self.ctx }
110 .get_token_with_options(options)
111 .await
112 }
113
114 /// Active session id, if signed in and available.
115 pub fn session_id(&self) -> Option<String> {
116 self.inner.read().session_id.clone()
117 }
118
119 /// Active organization id, if any.
120 pub fn org_id(&self) -> Option<String> {
121 self.inner.read().org_id.clone()
122 }
123
124 /// Active organization slug, if any.
125 pub fn org_slug(&self) -> Option<String> {
126 self.inner.read().org_slug.clone()
127 }
128
129 /// Organization role from verified server auth, if any.
130 pub fn org_role(&self) -> Option<String> {
131 self.inner.read().org_role.clone()
132 }
133
134 /// Organization permissions from verified server auth.
135 pub fn org_permissions(&self) -> Vec<String> {
136 self.inner.read().org_permissions.clone()
137 }
138
139 /// True if the auth state includes the given server-verified org role.
140 pub fn has_role(&self, role: &str) -> bool {
141 self.inner.read().has_role(role)
142 }
143
144 /// True if the auth state includes the given server-verified org permission.
145 pub fn has_permission(&self, permission: &str) -> bool {
146 self.inner.read().has_permission(permission)
147 }
148
149 /// True if the auth state satisfies a rendering auth requirement.
150 pub fn has(&self, requirement: &AuthRequirement) -> bool {
151 self.inner.read().has(requirement)
152 }
153
154 /// Sign out after Clerk lifecycle loadedness.
155 ///
156 /// This mirrors Clerk React's `useAuth().signOut()` convenience. Failures
157 /// from the scheduled browser action are surfaced through
158 /// [`use_clerk_error`]. Use [`UseAuth::try_sign_out`] when the caller needs
159 /// to await completion or handle errors locally.
160 pub fn sign_out(&self) {
161 self.sign_out_with_options(serde_json::Value::Null);
162 }
163
164 /// Sign out with Clerk `signOut(...)` options after Clerk lifecycle loadedness.
165 pub fn sign_out_with_options(&self, options: impl Into<serde_json::Value>) {
166 ClerkActions { ctx: self.ctx }.sign_out_with_options(options);
167 }
168
169 /// Sign out and return any lifecycle or clerk-js error.
170 pub async fn try_sign_out(&self) -> Result<(), ClerkError> {
171 self.try_sign_out_with_options(serde_json::Value::Null)
172 .await
173 }
174
175 /// Sign out with Clerk `signOut(...)` options and return any error.
176 pub async fn try_sign_out_with_options(
177 &self,
178 options: impl Into<serde_json::Value>,
179 ) -> Result<(), ClerkError> {
180 ClerkActions { ctx: self.ctx }
181 .try_sign_out_with_options(options)
182 .await
183 }
184}
185
186/// Options for [`use_auth_with_options`], mirroring the option object Clerk
187/// React's `useAuth(...)` accepts.
188///
189/// Construct with [`UseAuthOptions::new`] and chain setters; the struct is
190/// `#[non_exhaustive]` so new options can be added without a breaking release.
191#[derive(Clone, Debug, PartialEq, Eq)]
192#[non_exhaustive]
193pub struct UseAuthOptions {
194 treat_pending_as_signed_out: bool,
195}
196
197impl Default for UseAuthOptions {
198 fn default() -> Self {
199 // clerk-js treats pending sessions as signed out by default; matching
200 // that here keeps `use_auth()` consistent with the control components.
201 Self {
202 treat_pending_as_signed_out: true,
203 }
204 }
205}
206
207impl UseAuthOptions {
208 /// Options with clerk-js defaults (`treat_pending_as_signed_out = true`).
209 pub fn new() -> Self {
210 Self::default()
211 }
212
213 /// Set whether a session with pending after-auth tasks is treated as signed
214 /// out. `true` (the default) matches clerk-js; `false` reads a pending
215 /// session as signed in.
216 pub fn treat_pending_as_signed_out(mut self, value: bool) -> Self {
217 self.treat_pending_as_signed_out = value;
218 self
219 }
220}
221
222/// Read the current app-visible auth state.
223///
224/// # Example
225///
226/// ```no_run
227/// use dioxus::prelude::*;
228/// use dioxus_clerk::*;
229///
230/// #[component]
231/// fn AccountActions() -> Element {
232/// let auth = use_auth();
233///
234/// rsx! {
235/// if auth.is_signed_in() {
236/// button { onclick: move |_| auth.sign_out(), "Sign out" }
237/// }
238/// }
239/// }
240/// ```
241pub fn use_auth() -> UseAuth {
242 use_auth_with_options(UseAuthOptions::new())
243}
244
245/// Read the current app-visible auth state with explicit [`UseAuthOptions`].
246///
247/// Mirrors Clerk React's `useAuth({ treatPendingAsSignedOut })`: passing
248/// `UseAuthOptions::new().treat_pending_as_signed_out(false)` makes
249/// `is_signed_in()`, `status()`, and `has(...)` read a pending session as
250/// signed in.
251///
252/// # Example
253///
254/// ```no_run
255/// use dioxus::prelude::*;
256/// use dioxus_clerk::*;
257///
258/// #[component]
259/// fn PendingAware() -> Element {
260/// let auth = use_auth_with_options(
261/// UseAuthOptions::new().treat_pending_as_signed_out(false),
262/// );
263///
264/// rsx! {
265/// if auth.is_signed_in() {
266/// p { "Signed in (pending tasks count as signed in here)." }
267/// }
268/// }
269/// }
270/// ```
271pub fn use_auth_with_options(options: UseAuthOptions) -> UseAuth {
272 let ctx = use_clerk_context();
273 UseAuth {
274 inner: auth_state_signal(ctx, options.treat_pending_as_signed_out),
275 ctx,
276 }
277}
278
279/// Generate the auth-resolution predicate set for resource state structs, so
280/// the semantics of loading/signed-out/signed-in are stated once for every
281/// state shape that carries an [`AuthStatus`].
282macro_rules! status_predicates {
283 ($($ty:ident),* $(,)?) => {$(
284 impl $ty {
285 /// The explicit auth resolution status.
286 pub fn status(&self) -> AuthStatus {
287 self.status
288 }
289
290 /// Whether clerk-js has finished loading on the client.
291 pub fn is_loaded(&self) -> bool {
292 self.is_loaded
293 }
294
295 /// True while auth has not resolved to signed-in or signed-out yet.
296 pub fn is_loading(&self) -> bool {
297 self.status.is_loading()
298 }
299
300 /// True only when auth has resolved and no active session is known.
301 pub fn is_signed_out(&self) -> bool {
302 self.status.is_signed_out()
303 }
304
305 /// Whether a session is active.
306 pub fn is_signed_in(&self) -> bool {
307 self.status.is_signed_in()
308 }
309 }
310 )*};
311}
312
313/// Generate the shared accessor set for reactive hook results wrapping a
314/// resource state signal. Resource-specific accessors (`user()`, `session()`)
315/// stay hand-written next to each wrapper.
316macro_rules! hook_state_accessors {
317 ($($wrapper:ident => $state:ident, $doc:literal;)*) => {$(
318 impl $wrapper {
319 #[doc = concat!("Return the current ", $doc, " state.")]
320 pub fn state(&self) -> $state {
321 self.inner.read().clone()
322 }
323
324 /// Return the underlying read-only Dioxus signal for advanced composition.
325 pub fn signal(&self) -> ReadSignal<$state> {
326 self.inner
327 }
328
329 /// Return the explicit auth resolution status.
330 pub fn status(&self) -> AuthStatus {
331 self.inner.read().status
332 }
333
334 /// True while auth has not resolved to signed-in or signed-out yet.
335 pub fn is_loading(&self) -> bool {
336 self.status().is_loading()
337 }
338
339 /// True only when auth has resolved and no active session is known.
340 pub fn is_signed_out(&self) -> bool {
341 self.status().is_signed_out()
342 }
343
344 /// Whether clerk-js has finished loading on the client.
345 pub fn is_loaded(&self) -> bool {
346 self.inner.read().is_loaded
347 }
348
349 /// Whether a session is active.
350 pub fn is_signed_in(&self) -> bool {
351 self.inner.read().is_signed_in()
352 }
353 }
354
355 impl std::fmt::Debug for $wrapper {
356 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
357 f.debug_struct(stringify!($wrapper))
358 .field("state", &*self.inner.peek())
359 .finish_non_exhaustive()
360 }
361 }
362 )*};
363}
364
365/// Generate a memoized resource state signal projecting Auth state plus one
366/// resource read out of the provider-owned runtime state.
367macro_rules! resource_state_signal {
368 ($($name:ident, $state:ident { $field:ident };)*) => {$(
369 fn $name() -> ReadSignal<$state> {
370 let ctx = use_clerk_context();
371 use_memo(move || {
372 let state = ctx.auth.read();
373 let auth = state.to_state();
374 $state {
375 status: auth.status,
376 is_loaded: state.is_loaded(),
377 $field: state.$field().cloned(),
378 }
379 })
380 .into()
381 }
382 )*};
383}
384
385/// Current-user state that distinguishes loading, signed-out,
386/// and signed-in-without-full-browser-user states.
387///
388/// Fields are read through accessors ([`status`](UserState::status),
389/// [`is_loaded`](UserState::is_loaded), [`user`](UserState::user)), mirroring
390/// [`AuthState`] so every read-model snapshot in the
391/// crate shares one convention.
392#[derive(Debug, Clone, PartialEq)]
393#[non_exhaustive]
394pub struct UserState {
395 pub(crate) status: AuthStatus,
396 pub(crate) is_loaded: bool,
397 pub(crate) user: Option<User>,
398}
399
400impl UserState {
401 /// Full clerk-js user details, available after browser hydration.
402 pub fn user(&self) -> Option<&User> {
403 self.user.as_ref()
404 }
405}
406
407status_predicates!(UserState, SessionState);
408
409resource_state_signal! {
410 user_state_signal, UserState { user };
411 session_state_signal, SessionState { session };
412}
413
414hook_state_accessors! {
415 UseUser => UserState, "user";
416 UseSession => SessionState, "session";
417}
418
419/// Reactive user hook result returned by [`use_user`].
420#[derive(Clone, Copy)]
421pub struct UseUser {
422 inner: ReadSignal<UserState>,
423}
424
425impl UseUser {
426 /// Full clerk-js user details, available after browser hydration.
427 pub fn user(&self) -> Option<User> {
428 self.inner.read().user.clone()
429 }
430}
431
432/// Read the current user together with loadedness and signed-in status.
433///
434/// This mirrors Clerk React's `useUser()` shape more closely than a bare
435/// `Option<User>` and should be preferred in app code.
436///
437/// # Example
438///
439/// ```no_run
440/// use dioxus::prelude::*;
441/// use dioxus_clerk::*;
442///
443/// #[component]
444/// fn Greeting() -> Element {
445/// let user = use_user();
446///
447/// if !user.is_loaded() {
448/// return rsx! { "Loading..." };
449/// }
450///
451/// rsx! {
452/// if let Some(user) = user.user() {
453/// p { "Hello {user.id}" }
454/// }
455/// }
456/// }
457/// ```
458pub fn use_user() -> UseUser {
459 UseUser {
460 inner: user_state_signal(),
461 }
462}
463
464/// Current-session state that distinguishes loading,
465/// signed-out, and signed-in-without-full-browser-session states.
466///
467/// Fields are read through accessors ([`status`](SessionState::status),
468/// [`is_loaded`](SessionState::is_loaded), [`session`](SessionState::session)),
469/// mirroring [`AuthState`] so every read-model snapshot
470/// in the crate shares one convention.
471#[derive(Debug, Clone, PartialEq)]
472#[non_exhaustive]
473pub struct SessionState {
474 pub(crate) status: AuthStatus,
475 pub(crate) is_loaded: bool,
476 pub(crate) session: Option<Session>,
477}
478
479impl SessionState {
480 /// Full clerk-js session details, available after browser hydration.
481 pub fn session(&self) -> Option<&Session> {
482 self.session.as_ref()
483 }
484}
485
486/// Reactive session hook result returned by [`use_session`].
487#[derive(Clone, Copy)]
488pub struct UseSession {
489 inner: ReadSignal<SessionState>,
490}
491
492impl UseSession {
493 /// Full clerk-js session details, available after browser hydration.
494 pub fn session(&self) -> Option<Session> {
495 self.inner.read().session.clone()
496 }
497}
498
499/// Read the current session together with loadedness and signed-in status.
500///
501/// This mirrors Clerk React's `useSession()` shape more closely than a bare
502/// `Option<Session>` and should be preferred in app code.
503///
504/// # Example
505///
506/// ```no_run
507/// use dioxus::prelude::*;
508/// use dioxus_clerk::*;
509///
510/// #[component]
511/// fn SessionId() -> Element {
512/// let session = use_session();
513///
514/// rsx! {
515/// if let Some(session) = session.session() {
516/// code { "{session.id}" }
517/// }
518/// }
519/// }
520/// ```
521pub fn use_session() -> UseSession {
522 UseSession {
523 inner: session_state_signal(),
524 }
525}
526
527/// Read the latest Clerk error, if initialization failed, a scheduled
528/// browser action failed, or startup found a non-fatal configuration
529/// problem (e.g. an SSR seed publishable-key mismatch). A fatal
530/// initialization failure wins over the recoverable kinds.
531pub fn use_clerk_error() -> ReadSignal<Option<ClerkError>> {
532 let ctx = use_clerk_context();
533 use_memo(move || ctx.current_error()).into()
534}
535
536/// Return a callback that clears the latest recoverable error (a
537/// scheduled-action failure or a non-fatal startup configuration warning).
538///
539/// Fatal initialization failures are terminal for the provider instance;
540/// nothing retries the load, so clearing them would only convert a visible
541/// error into a silent forever-loading state. They are therefore not cleared
542/// by this callback.
543pub fn use_clear_clerk_error() -> Callback<()> {
544 let ctx = use_clerk_context();
545 use_callback(move |()| {
546 let mut action_error = ctx.action_error;
547 action_error.set(None);
548 })
549}
550
551/// Lifecycle-aware browser actions for the current clerk-js singleton.
552///
553/// Actions scheduled through this type wait for Clerk lifecycle loadedness
554/// before touching clerk-js.
555///
556/// Each operation comes in two forms. The plain method (e.g. `sign_out`) is
557/// fire-and-forget: it schedules the action and returns immediately, so it
558/// drops into an event handler, and any failure is surfaced through
559/// [`use_clerk_error`]. The `try_`-prefixed method (e.g. `try_sign_out`) is
560/// awaited and hands the [`ClerkError`] back to the caller, for when it needs
561/// to sequence work or handle the error locally. Each also has a
562/// `_with_options` variant taking Clerk options.
563#[derive(Clone, Copy)]
564pub struct ClerkActions {
565 ctx: ClerkContext,
566}
567
568impl std::fmt::Debug for ClerkActions {
569 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
570 f.debug_struct("ClerkActions").finish_non_exhaustive()
571 }
572}
573
574/// Generate the four public entry points for one Clerk operation that takes
575/// options: fire-and-forget, fire-and-forget with options, awaited, and
576/// awaited with options. Every body lands on the same two Clerk action
577/// dispatch functions; the operation-to-JS mapping lives once in
578/// `ClerkBridge::run`.
579macro_rules! clerk_option_actions {
580 ($($doc:literal:
581 $name:ident, $with_options:ident,
582 $try_name:ident, $try_with_options:ident => $op:ident;)*) => {$(
583 #[doc = concat!($doc, " after Clerk lifecycle loadedness.")]
584 pub fn $name(&self) {
585 self.$with_options(serde_json::Value::Null);
586 }
587
588 #[doc = concat!($doc, " with options after Clerk lifecycle loadedness.")]
589 pub fn $with_options(&self, options: impl Into<serde_json::Value>) {
590 crate::actions::schedule(
591 self.ctx,
592 crate::actions::ClerkOperation::$op(options.into()),
593 );
594 }
595
596 #[doc = concat!($doc, " and return any lifecycle or clerk-js error.")]
597 pub async fn $try_name(&self) -> Result<(), ClerkError> {
598 self.$try_with_options(serde_json::Value::Null).await
599 }
600
601 #[doc = concat!($doc, " with options and return any error.")]
602 pub async fn $try_with_options(
603 &self,
604 options: impl Into<serde_json::Value>,
605 ) -> Result<(), ClerkError> {
606 crate::actions::try_run(
607 self.ctx,
608 crate::actions::ClerkOperation::$op(options.into()),
609 )
610 .await
611 }
612 )*};
613}
614
615/// Generate the two public entry points for one option-less Clerk operation.
616macro_rules! clerk_plain_actions {
617 ($($doc:literal: $name:ident, $try_name:ident => $op:ident;)*) => {$(
618 #[doc = concat!($doc, " after Clerk lifecycle loadedness.")]
619 pub fn $name(&self) {
620 crate::actions::schedule(self.ctx, crate::actions::ClerkOperation::$op);
621 }
622
623 #[doc = concat!($doc, " and return any lifecycle or clerk-js error.")]
624 pub async fn $try_name(&self) -> Result<(), ClerkError> {
625 crate::actions::try_run(self.ctx, crate::actions::ClerkOperation::$op).await
626 }
627 )*};
628}
629
630impl ClerkActions {
631 clerk_option_actions! {
632 "Open the Clerk sign-in modal":
633 open_sign_in, open_sign_in_with_options,
634 try_open_sign_in, try_open_sign_in_with_options => OpenSignIn;
635 "Open the Clerk sign-up modal":
636 open_sign_up, open_sign_up_with_options,
637 try_open_sign_up, try_open_sign_up_with_options => OpenSignUp;
638 "Open the Clerk user-profile modal":
639 open_user_profile, open_user_profile_with_options,
640 try_open_user_profile, try_open_user_profile_with_options => OpenUserProfile;
641 "Sign out":
642 sign_out, sign_out_with_options,
643 try_sign_out, try_sign_out_with_options => SignOut;
644 "Redirect to Clerk sign-in":
645 redirect_to_sign_in, redirect_to_sign_in_with_options,
646 try_redirect_to_sign_in, try_redirect_to_sign_in_with_options => RedirectToSignIn;
647 "Redirect to Clerk sign-up":
648 redirect_to_sign_up, redirect_to_sign_up_with_options,
649 try_redirect_to_sign_up, try_redirect_to_sign_up_with_options => RedirectToSignUp;
650 }
651
652 clerk_plain_actions! {
653 "Close the Clerk sign-in modal": close_sign_in, try_close_sign_in => CloseSignIn;
654 "Close the Clerk sign-up modal": close_sign_up, try_close_sign_up => CloseSignUp;
655 "Close the Clerk user-profile modal":
656 close_user_profile, try_close_user_profile => CloseUserProfile;
657 }
658
659 /// Get the active session token from clerk-js.
660 pub async fn get_token(&self) -> Result<Option<String>, ClerkError> {
661 self.get_token_with_options(serde_json::Value::Null).await
662 }
663
664 /// Get the active session token with Clerk `getToken(...)` options.
665 pub async fn get_token_with_options(
666 &self,
667 options: impl Into<serde_json::Value>,
668 ) -> Result<Option<String>, ClerkError> {
669 #[cfg(clerk_client)]
670 {
671 let options = options.into();
672 crate::lifecycle::run_async_bridge_action_after_loaded(
673 self.ctx,
674 move |bridge| async move { bridge.get_token(&options).await },
675 )
676 .await
677 }
678 #[cfg(not(clerk_client))]
679 {
680 let _ = options;
681 Err(ClerkError::UnsupportedTarget)
682 }
683 }
684}
685
686/// Library-level browser actions for descendants of `ClerkProvider`.
687///
688/// # Example
689///
690/// Use this for design-system buttons that own their own DOM element:
691///
692/// ```no_run
693/// use dioxus::prelude::*;
694/// use dioxus_clerk::*;
695///
696/// #[component]
697/// fn CustomSignInButton() -> Element {
698/// let clerk = use_clerk();
699///
700/// rsx! {
701/// button {
702/// class: "btn btn-primary",
703/// onclick: move |_| clerk.open_sign_in(),
704/// "Sign in"
705/// }
706/// }
707/// }
708/// ```
709pub fn use_clerk() -> ClerkActions {
710 ClerkActions {
711 ctx: use_clerk_context(),
712 }
713}
714
715#[cfg(test)]
716mod tests {
717 use super::UseAuthOptions;
718
719 #[test]
720 fn use_auth_options_default_treats_pending_as_signed_out() {
721 // clerk-js's default is `true`; Rust's `bool::default()` is `false`, so
722 // the default must be set explicitly or parity silently breaks.
723 assert_eq!(
724 UseAuthOptions::new(),
725 UseAuthOptions::new().treat_pending_as_signed_out(true)
726 );
727 assert_ne!(
728 UseAuthOptions::new(),
729 UseAuthOptions::new().treat_pending_as_signed_out(false)
730 );
731 }
732}