Auth flows
Drive sign-in, sign-up, recovery, invitation, and verification flows from code.
useSignIn()
useSignIn() is the stateful sign-in hook behind <SignInForm />, OtherSignInOptions, and the rest of the embedded sign-in flow. It creates sign-in attempts, keeps the latest in-progress attempt in memory, and exposes the continuation methods that move that attempt through verification, profile completion, SSO, or passkey sign-in.
export default function PasswordSignIn() { const { loading, signIn, signinAttempt } = useSignIn(); async function submit() { if (loading) { return; } await signIn.createStrategy('email')({ email: 'jane@example.com', password: 'correct horse battery staple', }); } return ( <div> <button onClick={submit}>Sign in</button> {signinAttempt ? <p>Current step: {signinAttempt.current_step}</p> : null} </div> );}›loading?: boolean | undefined;
loading?: boolean | undefined;›signIn?: { createStrategy; prepareVerification; completeVerification; completeProfile; identify; initEnterpriseSso } | undefined;
signIn?: { createStrategy; prepareVerification; completeVerification; completeProfile; identify; initEnterpriseSso } | undefined;›createStrategy?: (strategy: 'username' | 'email' | 'phone' | 'email_otp' | 'magic_link' | 'oauth' | 'passkey' | 'generic') => Function | undefined;
createStrategy?: (strategy: 'username' | 'email' | 'phone' | 'email_otp' | 'magic_link' | 'oauth' | 'passkey' | 'generic') => Function | undefined;›username?: ({ username: string; password: string }) => Promise<ApiResult<Session>> | undefined;
username?: ({ username: string; password: string }) => Promise<ApiResult<Session>> | undefined;›email?: ({ email: string; password: string }) => Promise<ApiResult<Session>> | undefined;
email?: ({ email: string; password: string }) => Promise<ApiResult<Session>> | undefined;›phone?: ({ phone: string }) => Promise<ApiResult<Session>> | undefined;
phone?: ({ phone: string }) => Promise<ApiResult<Session>> | undefined;›email_otp?: ({ email: string }) => Promise<ApiResult<Session>> | undefined;
email_otp?: ({ email: string }) => Promise<ApiResult<Session>> | undefined;›magic_link?: ({ email: string }) => Promise<ApiResult<Session>> | undefined;
magic_link?: ({ email: string }) => Promise<ApiResult<Session>> | undefined;›oauth?: ({ provider: OAuthProvider; redirectUri?: string }) => Promise<ApiResult<{ oauth_url: string; session: Session }>> | undefined;
oauth?: ({ provider: OAuthProvider; redirectUri?: string }) => Promise<ApiResult<{ oauth_url: string; session: Session }>> | undefined;›passkey?: () => Promise<ApiResult<Session>> | undefined;
passkey?: () => Promise<ApiResult<Session>> | undefined;›generic?: ({ email?: string; username?: string; password?: string; phone?: string; strategy?: string }) => Promise<ApiResult<Session>> | undefined;
generic?: ({ email?: string; username?: string; password?: string; phone?: string; strategy?: string }) => Promise<ApiResult<Session>> | undefined;›prepareVerification?: (params: { strategy: 'email_otp'; redirectUri?: string } | { strategy: 'phone_otp'; lastDigits?: string } | { strategy: 'magic_link'; redirectUri?: string }) => Promise<ApiResult<{ otp_sent?: boolean; masked_phone?: string; masked_email?: string; verification_method?: string }>> | undefined;
prepareVerification?: (params: { strategy: 'email_otp'; redirectUri?: string } | { strategy: 'phone_otp'; lastDigits?: string } | { strategy: 'magic_link'; redirectUri?: string }) => Promise<ApiResult<{ otp_sent?: boolean; masked_phone?: string; masked_email?: string; verification_method?: string }>> | undefined;›completeVerification?: (verificationCode: string) => Promise<Session> | undefined;
completeVerification?: (verificationCode: string) => Promise<Session> | undefined;›completeProfile?: (data: ProfileCompletionData) => Promise<Session> | undefined;
completeProfile?: (data: ProfileCompletionData) => Promise<Session> | undefined;›first_name?: string | undefined | undefined;
first_name?: string | undefined | undefined;›last_name?: string | undefined | undefined;
last_name?: string | undefined | undefined;›username?: string | undefined | undefined;
username?: string | undefined | undefined;›phone_number?: string | undefined | undefined;
phone_number?: string | undefined | undefined;›phone_country_code?: string | undefined | undefined;
phone_country_code?: string | undefined | undefined;›email?: string | undefined | undefined;
email?: string | undefined | undefined;›identify?: (identifier: string) => Promise<{ strategy: "sso" | "social" | "password"; connection_id?: string; idp_url?: string; provider?: string }> | undefined;
identify?: (identifier: string) => Promise<{ strategy: "sso" | "social" | "password"; connection_id?: string; idp_url?: string; provider?: string }> | undefined;›initEnterpriseSso?: (connectionId: string, redirectUri?: string) => Promise<{ sso_url: string; session: Session }> | undefined;
initEnterpriseSso?: (connectionId: string, redirectUri?: string) => Promise<{ sso_url: string; session: Session }> | undefined;›signinAttempt?: SigninAttempt | null | undefined;
signinAttempt?: SigninAttempt | null | undefined;›id?: string | undefined;
id?: string | undefined;›email?: string | undefined;
email?: string | undefined;›method?: 'plain' | 'sso' | 'passkey' | undefined;
method?: 'plain' | 'sso' | 'passkey' | undefined;›sso_provider?: 'x_oauth' | 'github_oauth' | 'gitlab_oauth' | 'google_oauth' | 'facebook_oauth' | 'microsoft_oauth' | 'linkedin_oauth' | 'discord_oauth' | undefined;
sso_provider?: 'x_oauth' | 'github_oauth' | 'gitlab_oauth' | 'google_oauth' | 'facebook_oauth' | 'microsoft_oauth' | 'linkedin_oauth' | 'discord_oauth' | undefined;›current_step?: 'verify_password' | 'verify_email' | 'verify_email_link' | 'verify_email_otp' | 'verify_phone' | 'verify_phone_otp' | 'verify_second_factor' | 'add_second_factor' | 'complete_profile' | undefined;
current_step?: 'verify_password' | 'verify_email' | 'verify_email_link' | 'verify_email_otp' | 'verify_phone' | 'verify_phone_otp' | 'verify_second_factor' | 'add_second_factor' | 'complete_profile' | undefined;›first_method_authenticated?: boolean | undefined;
first_method_authenticated?: boolean | undefined;›second_method_authenticated?: boolean | undefined;
second_method_authenticated?: boolean | undefined;›second_method_authentication_required?: boolean | undefined;
second_method_authentication_required?: boolean | undefined;›available_2fa_methods?: string[] | undefined | undefined;
available_2fa_methods?: string[] | undefined | undefined;›completed?: boolean | undefined;
completed?: boolean | undefined;›requires_completion?: boolean | undefined | undefined;
requires_completion?: boolean | undefined | undefined;›required_fields?: string[] | undefined | undefined;
required_fields?: string[] | undefined | undefined;›missing_fields?: string[] | undefined | undefined;
missing_fields?: string[] | undefined | undefined;›profile_completion_data?: ProfileCompletionData | undefined | undefined;
profile_completion_data?: ProfileCompletionData | undefined | undefined;›first_name?: string | undefined | undefined;
first_name?: string | undefined | undefined;›last_name?: string | undefined | undefined;
last_name?: string | undefined | undefined;›username?: string | undefined | undefined;
username?: string | undefined | undefined;›phone_number?: string | undefined | undefined;
phone_number?: string | undefined | undefined;›phone_country_code?: string | undefined | undefined;
phone_country_code?: string | undefined | undefined;›email?: string | undefined | undefined;
email?: string | undefined | undefined;›discardSignInAttempt?: () => void | undefined;
discardSignInAttempt?: () => void | undefined;›setSignInAttempt?: (attempt: SigninAttempt | null) => void | undefined;
setSignInAttempt?: (attempt: SigninAttempt | null) => void | undefined;useSignUp()
useSignUp() is the stateful sign-up hook behind <SignUpForm />. It creates the sign-up attempt, keeps the latest in-progress signup attempt in memory, prepares the verification step that comes next, completes OTP verification, and validates deployment invitations before the user submits the form.
export default function EmailSignUp() { const { loading, signUp, signupAttempt } = useSignUp(); async function submit() { if (loading) { return; } await signUp.create({ email: 'jane@example.com', password: 'CorrectHorseBatteryStaple123!', }); } return ( <div> <button onClick={submit}>Create account</button> {signupAttempt ? <p>Current step: {signupAttempt.current_step}</p> : null} </div> );}›loading?: boolean | undefined;
loading?: boolean | undefined;›signUp: { create; prepareVerification; completeVerification; validateDeploymentInvitation };
signUp: { create; prepareVerification; completeVerification; validateDeploymentInvitation };›create?: (params: SignUpParams) => Promise<ApiResult<unknown>> | undefined;
create?: (params: SignUpParams) => Promise<ApiResult<unknown>> | undefined;›prepareVerification?: (params: { strategy: 'email_otp'; redirectUri?: string } | { strategy: 'phone_otp'; lastDigits?: string }) => Promise<ApiResult<{ otp_sent?: boolean; masked_phone?: string; masked_email?: string; verification_method?: string }>> | undefined;
prepareVerification?: (params: { strategy: 'email_otp'; redirectUri?: string } | { strategy: 'phone_otp'; lastDigits?: string }) => Promise<ApiResult<{ otp_sent?: boolean; masked_phone?: string; masked_email?: string; verification_method?: string }>> | undefined;›completeVerification?: (verificationCode: string) => Promise<ApiResult<Session>> | undefined;
completeVerification?: (verificationCode: string) => Promise<ApiResult<Session>> | undefined;›validateDeploymentInvitation?: (token: string) => Promise<{ valid: boolean; first_name?: string; last_name?: string; email?: string; message?: string; error_code?: string }> | undefined;
validateDeploymentInvitation?: (token: string) => Promise<{ valid: boolean; first_name?: string; last_name?: string; email?: string; message?: string; error_code?: string }> | undefined;›valid?: boolean | undefined;
valid?: boolean | undefined;›first_name?: string | undefined | undefined;
first_name?: string | undefined | undefined;›last_name?: string | undefined | undefined;
last_name?: string | undefined | undefined;›email?: string | undefined | undefined;
email?: string | undefined | undefined;›message?: string | undefined | undefined;
message?: string | undefined | undefined;›error_code?: string | undefined | undefined;
error_code?: string | undefined | undefined;›signupAttempt: SignupAttempt | null;
signupAttempt: SignupAttempt | null;›id?: string | undefined;
id?: string | undefined;›first_name?: string | undefined;
first_name?: string | undefined;›last_name?: string | undefined;
last_name?: string | undefined;›email?: string | undefined;
email?: string | undefined;›username?: string | undefined;
username?: string | undefined;›phone_number?: string | undefined;
phone_number?: string | undefined;›required_fields?: string[] | undefined;
required_fields?: string[] | undefined;›missing_fields?: string[] | undefined;
missing_fields?: string[] | undefined;›current_step?: 'verify_email' | 'verify_phone' | 'verify_authenticator' | undefined;
current_step?: 'verify_email' | 'verify_phone' | 'verify_authenticator' | undefined;›remaining_steps?: ('verify_email' | 'verify_phone' | 'verify_authenticator')[] | undefined;
remaining_steps?: ('verify_email' | 'verify_phone' | 'verify_authenticator')[] | undefined;›completed?: boolean | undefined;
completed?: boolean | undefined;›discardSignupAttempt: () => void;
discardSignupAttempt: () => void;useSSOCallback()
useSSOCallback() is the headless callback hook behind <SSOCallback />. It reads the OAuth query params on mount, decides whether the callback belongs to a sign-in flow or a social-connection flow, exchanges the callback with the backend, and exposes the returned session, redirect target, and any unfinished sign-in attempt.
export default function SsoCallbackPage() { const { loading, error, processed, signinAttempt, redirectUri } = useSSOCallback(); if (!processed || loading) { return <p>Completing sign in...</p>; } if (error) { return <p>{error.message}</p>; } return ( <div> <p>Callback processed.</p> {signinAttempt ? <p>Next step: {signinAttempt.current_step}</p> : null} {redirectUri ? <p>Redirect target: {redirectUri}</p> : null} </div> );}›loading: boolean;
loading: boolean;›error: Error | null;
error: Error | null;›session: Session | null;
session: Session | null;›id?: number | undefined;
id?: number | undefined;›active_signin?: SignIn | null | undefined;
active_signin?: SignIn | null | undefined;›id?: string | undefined;
id?: string | undefined;›user_id?: string | undefined;
user_id?: string | undefined;›active_organization_membership_id?: string | undefined;
active_organization_membership_id?: string | undefined;›active_workspace_membership_id?: string | undefined;
active_workspace_membership_id?: string | undefined;›expiresAt?: string | undefined;
expiresAt?: string | undefined;›lastActiveAt?: string | undefined;
lastActiveAt?: string | undefined;›user?: CurrentUser | undefined;
user?: CurrentUser | undefined;›id?: string | undefined;
id?: string | undefined;›first_name?: string | undefined;
first_name?: string | undefined;›last_name?: string | undefined;
last_name?: string | undefined;›username?: string | undefined;
username?: string | undefined;›primary_email_address?: UserEmailAddress | undefined;
primary_email_address?: UserEmailAddress | undefined;›email?: string | undefined;
email?: string | undefined;›verified?: boolean | undefined;
verified?: boolean | undefined;›primary_phone_number?: UserPhoneNumber | undefined;
primary_phone_number?: UserPhoneNumber | undefined;›phone_number?: string | undefined;
phone_number?: string | undefined;›verified?: boolean | undefined;
verified?: boolean | undefined;›has_password?: boolean | undefined;
has_password?: boolean | undefined;›has_passkeys?: boolean | undefined;
has_passkeys?: boolean | undefined;›signins?: SignIn[] | undefined | undefined;
signins?: SignIn[] | undefined | undefined;›[].id?: string | undefined;
[].id?: string | undefined;›[].active_organization_membership_id?: string | undefined;
[].active_organization_membership_id?: string | undefined;›[].active_workspace_membership_id?: string | undefined;
[].active_workspace_membership_id?: string | undefined;›[].expiresAt?: string | undefined;
[].expiresAt?: string | undefined;›[].lastActiveAt?: string | undefined;
[].lastActiveAt?: string | undefined;›[].browser?: string | undefined;
[].browser?: string | undefined;›[].device?: string | undefined;
[].device?: string | undefined;›[].city?: string | undefined;
[].city?: string | undefined;›[].region?: string | undefined;
[].region?: string | undefined;›[].country?: string | undefined;
[].country?: string | undefined;›signin_attempts?: SigninAttempt[] | undefined | undefined;
signin_attempts?: SigninAttempt[] | undefined | undefined;›[].id?: string | undefined;
[].id?: string | undefined;›[].email?: string | undefined;
[].email?: string | undefined;›[].method?: 'plain' | 'sso' | 'passkey' | undefined;
[].method?: 'plain' | 'sso' | 'passkey' | undefined;›[].sso_provider?: 'x_oauth' | 'github_oauth' | 'gitlab_oauth' | 'google_oauth' | 'facebook_oauth' | 'microsoft_oauth' | 'linkedin_oauth' | 'discord_oauth' | undefined;
[].sso_provider?: 'x_oauth' | 'github_oauth' | 'gitlab_oauth' | 'google_oauth' | 'facebook_oauth' | 'microsoft_oauth' | 'linkedin_oauth' | 'discord_oauth' | undefined;›[].current_step?: 'verify_password' | 'verify_email' | 'verify_email_link' | 'verify_email_otp' | 'verify_phone' | 'verify_phone_otp' | 'verify_second_factor' | 'add_second_factor' | 'complete_profile' | undefined;
[].current_step?: 'verify_password' | 'verify_email' | 'verify_email_link' | 'verify_email_otp' | 'verify_phone' | 'verify_phone_otp' | 'verify_second_factor' | 'add_second_factor' | 'complete_profile' | undefined;›[].first_method_authenticated?: boolean | undefined;
[].first_method_authenticated?: boolean | undefined;›[].second_method_authenticated?: boolean | undefined;
[].second_method_authenticated?: boolean | undefined;›[].second_method_authentication_required?: boolean | undefined;
[].second_method_authentication_required?: boolean | undefined;›[].available_2fa_methods?: string[] | undefined | undefined;
[].available_2fa_methods?: string[] | undefined | undefined;›[].completed?: boolean | undefined;
[].completed?: boolean | undefined;›[].requires_completion?: boolean | undefined | undefined;
[].requires_completion?: boolean | undefined | undefined;›[].missing_fields?: string[] | undefined | undefined;
[].missing_fields?: string[] | undefined | undefined;›[].required_fields?: string[] | undefined | undefined;
[].required_fields?: string[] | undefined | undefined;›redirectUri: string | null;
redirectUri: string | null;›processed: boolean;
processed: boolean;›signinAttempt: SigninAttempt | null;
signinAttempt: SigninAttempt | null;›id?: string | undefined;
id?: string | undefined;›method?: 'plain' | 'sso' | 'passkey' | undefined;
method?: 'plain' | 'sso' | 'passkey' | undefined;›current_step?: 'verify_password' | 'verify_email' | 'verify_email_link' | 'verify_email_otp' | 'verify_phone' | 'verify_phone_otp' | 'verify_second_factor' | 'add_second_factor' | 'complete_profile' | undefined;
current_step?: 'verify_password' | 'verify_email' | 'verify_email_link' | 'verify_email_otp' | 'verify_phone' | 'verify_phone_otp' | 'verify_second_factor' | 'add_second_factor' | 'complete_profile' | undefined;›completed?: boolean | undefined;
completed?: boolean | undefined;›second_method_authentication_required?: boolean | undefined;
second_method_authentication_required?: boolean | undefined;›available_2fa_methods?: string[] | undefined | undefined;
available_2fa_methods?: string[] | undefined | undefined;›requires_completion?: boolean | undefined | undefined;
requires_completion?: boolean | undefined | undefined;useWaitlist()
useWaitlist() is the headless waitlist hook behind <WaitlistForm />. It submits the waitlist fields to the active deployment and returns the created waitlist entry so the page can decide how to show success.
export default function JoinWaitlist() { const { loading, joinWaitlist } = useWaitlist(); async function submit() { if (loading) { return; } await joinWaitlist({ first_name: 'Jane', last_name: 'Doe', email: 'jane@example.com', }); } return <button onClick={submit}>Join waitlist</button>;}›loading: boolean;
loading: boolean;›joinWaitlist: (params: { first_name: string; last_name: string; email: string }) => Promise<ApiResult<WaitlistResponse>>;
joinWaitlist: (params: { first_name: string; last_name: string; email: string }) => Promise<ApiResult<WaitlistResponse>>;›first_name?: string | undefined;
first_name?: string | undefined;›last_name?: string | undefined;
last_name?: string | undefined;›email?: string | undefined;
email?: string | undefined;›message?: string | undefined;
message?: string | undefined;›entry?: WaitlistEntry | undefined;
entry?: WaitlistEntry | undefined;›id?: string | undefined;
id?: string | undefined;›deployment_id?: number | undefined;
deployment_id?: number | undefined;›email_address?: string | undefined;
email_address?: string | undefined;›first_name?: string | undefined;
first_name?: string | undefined;›last_name?: string | undefined;
last_name?: string | undefined;›created_at?: string | undefined;
created_at?: string | undefined;›updated_at?: string | undefined;
updated_at?: string | undefined;useForgotPassword()
useForgotPassword() is the headless password-recovery hook behind ForgotPassword. It starts the reset flow for an email address, verifies the OTP that comes back to the user, and then exchanges the reset token for a new session when the password is changed.
export default function ForgotPasswordFlow() { const { loading, forgotPassword, verifyOtp, resetPassword } = useForgotPassword(); async function run() { if (loading) { return; } await forgotPassword('jane@example.com'); const verification = await verifyOtp('jane@example.com', '123456'); if ('data' in verification) { await resetPassword(verification.data.token, 'NewPassword123!'); } } return <button onClick={run}>Reset password</button>;}›loading: boolean;
loading: boolean;›forgotPassword: (email: string) => Promise<ApiResult<{}>>;
forgotPassword: (email: string) => Promise<ApiResult<{}>>;›verifyOtp: (email: string, otp: string) => Promise<ApiResult<{ token: string }>>;
verifyOtp: (email: string, otp: string) => Promise<ApiResult<{ token: string }>>;›token?: string | undefined;
token?: string | undefined;›resetPassword: (token: string, password: string) => Promise<ApiResult<Session>>;
resetPassword: (token: string, password: string) => Promise<ApiResult<Session>>;›id?: number | undefined;
id?: number | undefined;›active_signin?: SignIn | null | undefined;
active_signin?: SignIn | null | undefined;›id?: string | undefined;
id?: string | undefined;›active_organization_membership_id?: string | undefined;
active_organization_membership_id?: string | undefined;›active_workspace_membership_id?: string | undefined;
active_workspace_membership_id?: string | undefined;›expiresAt?: string | undefined;
expiresAt?: string | undefined;›lastActiveAt?: string | undefined;
lastActiveAt?: string | undefined;›signin_attempts?: SigninAttempt[] | undefined | undefined;
signin_attempts?: SigninAttempt[] | undefined | undefined;›[].id?: string | undefined;
[].id?: string | undefined;›[].current_step?: 'verify_password' | 'verify_email' | 'verify_email_link' | 'verify_email_otp' | 'verify_phone' | 'verify_phone_otp' | 'verify_second_factor' | 'add_second_factor' | 'complete_profile' | undefined;
[].current_step?: 'verify_password' | 'verify_email' | 'verify_email_link' | 'verify_email_otp' | 'verify_phone' | 'verify_phone_otp' | 'verify_second_factor' | 'add_second_factor' | 'complete_profile' | undefined;›[].completed?: boolean | undefined;
[].completed?: boolean | undefined;›[].second_method_authentication_required?: boolean | undefined;
[].second_method_authentication_required?: boolean | undefined;useMagicLinkVerification()
useMagicLinkVerification() is the headless verification hook behind <MagicLinkVerification />. It verifies the callback token and attempt pair, tracks whether verification is still running, and exposes a simple success state for the page that owns the redirect after verification completes.
export default function MagicLinkPage() { const { loading, success, verifyMagicLink } = useMagicLinkVerification(); async function verify() { await verifyMagicLink({ token: 'magic-link-token', attempt: 'signin-attempt-id', redirectUri: window.location.href, }); } return ( <div> <button onClick={verify}>Verify magic link</button> {loading ? <p>Verifying…</p> : null} {success === true ? <p>Verified.</p> : null} </div> );}›loading: boolean;
loading: boolean;›verifyMagicLink: (params: { token?: string; attempt?: string; redirectUri?: string }) => Promise<ApiResult<{}>>;
verifyMagicLink: (params: { token?: string; attempt?: string; redirectUri?: string }) => Promise<ApiResult<{}>>;›token?: string | undefined | undefined;
token?: string | undefined | undefined;›attempt?: string | undefined | undefined;
attempt?: string | undefined | undefined;›redirectUri?: string | undefined | undefined;
redirectUri?: string | undefined | undefined;›success: boolean | null;
success: boolean | null;useInvitation()
useInvitation() is the headless invitation-acceptance hook behind <AcceptInvite />. It accepts an invitation token, stores the last returned invitation result, exposes a loading state for the active request, and keeps a reset path so the page can clear the last result before trying again.
export default function InvitationPage() { const { acceptInvitation, invitationData, loading, error } = useInvitation(); async function accept() { await acceptInvitation('invite-token'); } return ( <div> <button onClick={accept} disabled={loading}> Accept invitation </button> {error ? <p>{error}</p> : null} {invitationData?.organization ? <p>{invitationData.organization.name}</p> : null} </div> );}›acceptInvitation: (token: string) => Promise<AcceptInvitationResponse>;
acceptInvitation: (token: string) => Promise<AcceptInvitationResponse>;›organization?: { id: string; name: string } | undefined | undefined;
organization?: { id: string; name: string } | undefined | undefined;›id?: string | undefined;
id?: string | undefined;›name?: string | undefined;
name?: string | undefined;›workspace?: { id: string; name: string } | undefined | undefined;
workspace?: { id: string; name: string } | undefined | undefined;›id?: string | undefined;
id?: string | undefined;›name?: string | undefined;
name?: string | undefined;›signin_id?: string | undefined | undefined;
signin_id?: string | undefined | undefined;›already_member?: boolean | undefined | undefined;
already_member?: boolean | undefined | undefined;›message?: string | undefined | undefined;
message?: string | undefined | undefined;›requires_signin?: boolean | undefined | undefined;
requires_signin?: boolean | undefined | undefined;›invited_email?: string | undefined | undefined;
invited_email?: string | undefined | undefined;›error_code?: string | undefined | undefined;
error_code?: string | undefined | undefined;›invitationData: AcceptInvitationResponse | null;
invitationData: AcceptInvitationResponse | null;›organization?: { id: string; name: string } | undefined | undefined;
organization?: { id: string; name: string } | undefined | undefined;›workspace?: { id: string; name: string } | undefined | undefined;
workspace?: { id: string; name: string } | undefined | undefined;›signin_id?: string | undefined | undefined;
signin_id?: string | undefined | undefined;›already_member?: boolean | undefined | undefined;
already_member?: boolean | undefined | undefined;›message?: string | undefined | undefined;
message?: string | undefined | undefined;›requires_signin?: boolean | undefined | undefined;
requires_signin?: boolean | undefined | undefined;›invited_email?: string | undefined | undefined;
invited_email?: string | undefined | undefined;›error_code?: string | undefined | undefined;
error_code?: string | undefined | undefined;›loading: boolean;
loading: boolean;›error: string | null;
error: string | null;›reset: () => void;
reset: () => void;useUserSignins()
useUserSignins() is the headless session-list hook behind the active-sessions section in <ManageAccount />. It loads the current user’s sign-in records with SWR, exposes a way to sign out one of those records, and keeps a manual refetch path so the UI can refresh after a mutation.
export default function ActiveSessions() { const { signins, loading, removeSignin } = useUserSignins(); async function endFirstSession() { if (!signins?.length) { return; } await removeSignin(signins[0].id); } return ( <div> <button onClick={endFirstSession} disabled={loading}> End first session </button> <p>Sessions: {signins?.length ?? 0}</p> </div> );}›signins: SignIn[] | undefined;
signins: SignIn[] | undefined;›[].id?: string | undefined;
[].id?: string | undefined;›[].user_id?: string | undefined;
[].user_id?: string | undefined;›[].active_organization_membership_id?: string | undefined;
[].active_organization_membership_id?: string | undefined;›[].active_workspace_membership_id?: string | undefined;
[].active_workspace_membership_id?: string | undefined;›[].expiresAt?: string | undefined;
[].expiresAt?: string | undefined;›[].lastActiveAt?: string | undefined;
[].lastActiveAt?: string | undefined;›[].ipAddress?: string | undefined;
[].ipAddress?: string | undefined;›[].browser?: string | undefined;
[].browser?: string | undefined;›[].device?: string | undefined;
[].device?: string | undefined;›[].city?: string | undefined;
[].city?: string | undefined;›[].region?: string | undefined;
[].region?: string | undefined;›[].regionCode?: string | undefined;
[].regionCode?: string | undefined;›[].country?: string | undefined;
[].country?: string | undefined;›[].countryCode?: string | undefined;
[].countryCode?: string | undefined;›[].user?: CurrentUser | undefined;
[].user?: CurrentUser | undefined;›id?: string | undefined;
id?: string | undefined;›first_name?: string | undefined;
first_name?: string | undefined;›last_name?: string | undefined;
last_name?: string | undefined;›username?: string | undefined;
username?: string | undefined;›error: Error | null;
error: Error | null;›removeSignin: (id: string) => Promise<ApiResult<unknown>>;
removeSignin: (id: string) => Promise<ApiResult<unknown>>;›refetch: () => Promise<SignIn[] | undefined>;
refetch: () => Promise<SignIn[] | undefined>;›loading: boolean;
loading: boolean;