useSSOCallback() hook
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.Usage
The following example shows a basic usage of useSSOCallback().
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> );}Return value
The hook returns the following fields and methods.
›loading: boolean;
loading: boolean;Whether the callback exchange is currently running.
›error: Error | null;
error: Error | null;Callback error when the OAuth params are missing, invalid, or rejected.
›session: Session | null;
session: Session | null;Session returned by the callback exchange.
›id?: number | undefined;
id?: number | undefined;Session identifier.
›active_signin?: SignIn | null | undefined;
active_signin?: SignIn | null | undefined;Active sign-in for the returned session.
›id?: string | undefined;
id?: string | undefined;Active sign-in identifier.
›user_id?: string | undefined;
user_id?: string | undefined;User identifier attached to the active sign-in.
›active_organization_membership_id?: string | undefined;
active_organization_membership_id?: string | undefined;Active organization membership for this sign-in.
›active_workspace_membership_id?: string | undefined;
active_workspace_membership_id?: string | undefined;Active workspace membership for this sign-in.
›expiresAt?: string | undefined;
expiresAt?: string | undefined;Sign-in expiry timestamp.
›lastActiveAt?: string | undefined;
lastActiveAt?: string | undefined;Last activity timestamp for the sign-in.
›user?: CurrentUser | undefined;
user?: CurrentUser | undefined;User record attached to the active sign-in.
›id?: string | undefined;
id?: string | undefined;Current user identifier.
›first_name?: string | undefined;
first_name?: string | undefined;User first name.
›last_name?: string | undefined;
last_name?: string | undefined;User last name.
›username?: string | undefined;
username?: string | undefined;Username when one is set.
›primary_email_address?: UserEmailAddress | undefined;
primary_email_address?: UserEmailAddress | undefined;Primary email-address record.
›email?: string | undefined;
email?: string | undefined;Primary email address value.
›verified?: boolean | undefined;
verified?: boolean | undefined;Whether the primary email address has been verified.
›primary_phone_number?: UserPhoneNumber | undefined;
primary_phone_number?: UserPhoneNumber | undefined;Primary phone-number record when one exists.
›phone_number?: string | undefined;
phone_number?: string | undefined;Primary phone number value.
›verified?: boolean | undefined;
verified?: boolean | undefined;Whether the primary phone number has been verified.
›has_password?: boolean | undefined;
has_password?: boolean | undefined;Whether the user has a password set.
›has_passkeys?: boolean | undefined;
has_passkeys?: boolean | undefined;Whether the user has passkeys registered.
›signins?: SignIn[] | undefined | undefined;
signins?: SignIn[] | undefined | undefined;Sign-ins attached to the returned session.
›[].id?: string | undefined;
[].id?: string | undefined;Sign-in identifier.
›[].active_organization_membership_id?: string | undefined;
[].active_organization_membership_id?: string | undefined;Active organization membership for the sign-in.
›[].active_workspace_membership_id?: string | undefined;
[].active_workspace_membership_id?: string | undefined;Active workspace membership for the sign-in.
›[].expiresAt?: string | undefined;
[].expiresAt?: string | undefined;Sign-in expiry timestamp.
›[].lastActiveAt?: string | undefined;
[].lastActiveAt?: string | undefined;Last activity timestamp.
›[].browser?: string | undefined;
[].browser?: string | undefined;Browser recorded for the sign-in.
›[].device?: string | undefined;
[].device?: string | undefined;Device recorded for the sign-in.
›[].city?: string | undefined;
[].city?: string | undefined;City recorded for the sign-in.
›[].region?: string | undefined;
[].region?: string | undefined;Region recorded for the sign-in.
›[].country?: string | undefined;
[].country?: string | undefined;Country recorded for the sign-in.
›signin_attempts?: SigninAttempt[] | undefined | undefined;
signin_attempts?: SigninAttempt[] | undefined | undefined;Sign-in attempts returned with the session.
›[].id?: string | undefined;
[].id?: string | undefined;Sign-in-attempt identifier.
›[].email?: string | undefined;
[].email?: string | undefined;Email associated with the attempt.
›[].method?: 'plain' | 'sso' | 'passkey' | undefined;
[].method?: 'plain' | 'sso' | 'passkey' | undefined;High-level sign-in method behind the attempt.
›[].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;Provider attached to the attempt when relevant.
›[].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;Current step for the attempt.
›[].first_method_authenticated?: boolean | undefined;
[].first_method_authenticated?: boolean | undefined;Whether the first factor has completed.
›[].second_method_authenticated?: boolean | undefined;
[].second_method_authenticated?: boolean | undefined;Whether the second factor has completed.
›[].second_method_authentication_required?: boolean | undefined;
[].second_method_authentication_required?: boolean | undefined;Whether the attempt still requires a second factor.
›[].available_2fa_methods?: string[] | undefined | undefined;
[].available_2fa_methods?: string[] | undefined | undefined;Available second-factor methods.
›[].completed?: boolean | undefined;
[].completed?: boolean | undefined;Whether the attempt has fully finished.
›[].requires_completion?: boolean | undefined | undefined;
[].requires_completion?: boolean | undefined | undefined;Whether the sign-in still needs profile completion.
›[].missing_fields?: string[] | undefined | undefined;
[].missing_fields?: string[] | undefined | undefined;Fields still missing from the attempt.
›[].required_fields?: string[] | undefined | undefined;
[].required_fields?: string[] | undefined | undefined;Fields required for the attempt to complete.
›redirectUri: string | null;
redirectUri: string | null;Redirect target returned by the callback exchange when one is available.
›processed: boolean;
processed: boolean;Whether the hook has already inspected the callback URL and finished its first processing pass.
›signinAttempt: SigninAttempt | null;
signinAttempt: SigninAttempt | null;Latest sign-in attempt returned by the callback exchange when the sign-in flow still has work left to do.
›id?: string | undefined;
id?: string | undefined;Stable identifier for the returned attempt.
›method?: 'plain' | 'sso' | 'passkey' | undefined;
method?: 'plain' | 'sso' | 'passkey' | undefined;Sign-in method attached to the callback result.
›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;Current step for the unfinished sign-in flow.
›completed?: boolean | undefined;
completed?: boolean | undefined;Whether the returned attempt has fully finished.
›second_method_authentication_required?: boolean | undefined;
second_method_authentication_required?: boolean | undefined;Whether the returned attempt still requires a second factor.
›available_2fa_methods?: string[] | undefined | undefined;
available_2fa_methods?: string[] | undefined | undefined;Available second-factor methods when the attempt is waiting for one.
›requires_completion?: boolean | undefined | undefined;
requires_completion?: boolean | undefined | undefined;Whether the sign-in still needs profile completion.
How it works
The hook processes the callback only once per mount. The
processed flag prevents the same URL from being exchanged multiple times while the page re-renders.It accepts two kinds of callback results. A
sign_in callback returns session state for authentication, while a connect_social callback is used to finish a social-account connection flow for an already signed-in user.The hook does not navigate on its own. It only exposes the returned state. Components such as <SSOCallback /> decide whether to resume an unfinished sign-in attempt, continue to a redirect target, or show an error state.
When the callback returns a session with unfinished sign-in attempts, the hook surfaces the latest one as
signinAttempt so the UI can hand the user back into the right verification or completion step.If the callback URL does not contain OAuth data, the hook marks itself as processed and returns an error instead of waiting forever.
When to use it
Examples
Resume an unfinished sign-in attempt
export default function ResumeSsoSignIn() { const { processed, loading, signinAttempt } = useSSOCallback(); const { navigateToSignIn } = useNavigation(); if (!processed || loading || !signinAttempt || signinAttempt.completed) { return null; } return ( <button onClick={() => navigateToSignIn(window.location.href)}> Continue sign in </button> );}Handle an SSO callback error
export default function SsoErrorState() { const { processed, loading, error } = useSSOCallback(); if (!processed || loading || !error) { return null; } return <p>{error.message}</p>;}