<SignInForm/> component

<SignInForm /> is the shared embedded sign-in surface. It sits on top of SignInProvider, useSignIn(), useSession(), deployment auth settings, and the shared navigation helpers, so the form can move between identifier entry, password entry, other auth strategies, verification, passkeys, profile completion, multi-session selection, and redirect handling without extra wiring from the app.

Usage

The following example shows a basic usage of <SignInForm />.

import { DefaultStylesProvider, SignInForm } from '@wacht/nextjs';export default function SignInFormUsage() {  return (    <>      <DefaultStylesProvider>        <SignInForm />      </DefaultStylesProvider>    </>  );}

Entry and state

The component wraps its content in SignInProvider, which tracks the current step, the first-factor strategy, the enabled social providers, and the identifier state.
The provider resolves the deployment-backed auth rules before the form decides what to show. The form does not invent its own capabilities.
  • If the user already has an active sign-in and multi-session support is disabled, the component redirects instead of showing the form.
  • If the deployment enables passkey prompting on auth and the signed-in user does not yet have a passkey, the form pauses and shows the passkey prompt before the final redirect.

Primary screen

The main screen renders the sign-in title, the optional current-account hints, the social sign-in buttons, the passkey button, and the credential form. Those pieces appear only when the deployment enables them.
Social auth buttons are grouped and laid out dynamically. With one provider the button reads like a full call to action, and with several providers it collapses into compact provider labels.
The “other methods” screen is a separate branch with its own back path. It is used when the main view would be too crowded or the user wants a different strategy entirely.

Verification and recovery

The identifier step can branch into password, OTP, magic-link, social, SSO, or passkey flows depending on deployment settings and what the user enters.
The forgot-password path is part of the sign-in component. It can start the password reset flow, verify the OTP, and send the user back into sign-in if a follow-up attempt is still incomplete.
Verification states come from the sign-in attempt. The component knows how to resume email OTP, phone OTP, magic-link, 2FA, and profile-completion steps.
  • If a sign-in attempt returns an incomplete profile, the component hands off to profile completion instead of staying on the sign-in screen.
  • If a sign-in attempt requires second-factor verification, the component hands off to the two-factor flow and keeps the attempt identifier alive through that transition.
  • Passkey prompting is separate from passkey sign-in. One is the login method itself; the other is a follow-up prompt after sign-in to register a passkey for later.

Session-aware paths

When the current session already contains sign-ins, the form can surface existing accounts and offer continue-as and more-accounts paths instead of starting from scratch.
Continue-as uses the active session’s sign-in list and keeps the current redirect target intact. More accounts sends the user to the account-selection route when that route is configured.
Sign-in tickets and incomplete sign-in attempts are both resumable through query parameters, which is how impersonation and mid-flow redirects get restored.
  • If the page receives a ticket, the component exchanges it for a session before it resolves the redirect target.
  • If the page receives a signin_attempt_id, it rehydrates the attempt from the session and resumes the correct verification branch.

Redirects and deployment rules

SSO error query parameters are handled on entry so the form can show the error state and let the user retry without breaking the route.
The SSO branch uses the provider connection returned by identifier lookup to send the user to the right identity provider, and it preserves the redirect target when one is present.
Redirect handling always checks redirect_uri first, then deployment redirect URLs, then the deployment frontend host.
  • In staging, redirects keep __dev_session__ attached so the session survives the round trip.
  • The deployment auth settings are the real source of truth for which first-factor fields render. The form does not invent its own capabilities.

Examples

Basic embedded page

import { DefaultStylesProvider, SignInForm } from '@wacht/nextjs';export default function SignInFormBasicEmbeddedPage() {  return (    <>      <DefaultStylesProvider>        <SignInForm />      </DefaultStylesProvider>    </>  );}

Custom shell

export default function SignInPage() {  return (    <div className="mx-auto max-w-md py-12">      <h1>Sign in</h1>      <DefaultStylesProvider>        <SignInForm />      </DefaultStylesProvider>    </div>  );}

On this page