> ## Documentation Index
> Fetch the complete documentation index at: https://docs.nesolva.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Signup & Forgot Password

> Account creation, email verification, and password recovery flows.

`SignupForm` and `ForgotPasswordForm` are standalone components that handle their respective multi-step flows internally. Both use `ChallengeView` for email verification. Both require `<AilitaProvider>` as an ancestor to access merchant configuration and inject API credentials.

## Signup Flow

### How It Works

<Steps>
  <Step title="User fills the registration form">
    `SignupForm` collects firstName, lastName, email, password (optional when `loginMode` is `OTP_EMAIL`), and phone (optional). Password requirements: minimum 8 characters, must contain at least one letter and one number. The password field is hidden entirely when the merchant uses OTP-only authentication.
  </Step>

  <Step title="Library submits signup request">
    On submit, the library calls the signup API with the form data plus device fingerprint and behavioral biometrics — both collected automatically in the background before the user clicks submit. The `app` and `mid` tenant identifiers are injected from the merchant context automatically. You do not provide them.
  </Step>

  <Step title="Email verification">
    Two outcomes depending on the backend response:

    **1. challengeId returned** — `SignupForm` shows an inline `ChallengeView` where the user enters a 6-digit OTP sent to their email. After successful verification, `onSuccess(userId)` fires and the user is considered fully registered.

    **2. No challengeId** — `SignupForm` shows a "Check your email" message with an activation link instruction. The user must click the link in their email before they can log in. `onSuccess` does **not** fire in this case.
  </Step>

  <Step title="Account activated">
    After email verification (OTP or link), the account moves to active status and the user can log in via `LoginForm`.
  </Step>
</Steps>

<Warning>
  A signed-up user cannot log in until their email is verified. If your app redirects to the login page immediately after signup, display a message reminding the user to check their email first. Do not call `router.push('/dashboard')` inside `onSuccess` without confirming the user's email is already verified — the standard approach is to navigate to a "check your email" page instead.
</Warning>

### Post-Signup State

The table below shows what state the user account is in at each stage of the signup flow.

| After                        | User Status | Email Status      | Can Login? |
| ---------------------------- | ----------- | ----------------- | ---------- |
| Form submitted               | `ACTIVE`    | `VALIDATION_SENT` | No         |
| Email verified (OTP or link) | `ACTIVE`    | `VALIDATED`       | Yes        |

<Note>
  The `signupMode` of the merchant controls who can sign up. When set to `INVITATION_ONLY`, `SignupForm` shows a 403 error: "Registration on this platform is by invitation only." Users without a prior invitation cannot create accounts. The `signupMode` is configured on the backend — see [Provider Setup](/ailita/provider-setup) for details.
</Note>

### SignupForm Props

<ParamField body="layout" type="'full-screen' | 'side-screen'">
  Controls the visual layout. `full-screen` renders a centered card on a gray background. `side-screen` renders the form on the right half with a branded colored panel on the left (uses `--color-primary`). Defaults to `'full-screen'`.
</ParamField>

<ParamField body="onSuccess" type="(userId: string) => void">
  Fires after successful signup **and** email OTP verification. Receives the new user's ID. If the backend returns no `challengeId` (email link verification path), this callback does **not** fire — the user must navigate to login manually after clicking the link in their email.
</ParamField>

<ParamField body="onLoginClick" type="() => void">
  Optional. Fires when the user clicks "Already have an account? Log in." Use this to navigate back to your login page.
</ParamField>

<ParamField body="onChallengeRequired" type="(challengeId: string) => void">
  Optional. If provided, `SignupForm` does **not** render the inline `ChallengeView` after signup. Instead it calls this callback with the `challengeId` and stops — you are responsible for rendering `ChallengeView` in a custom location.

  <Note>
    This follows the same pattern as `LoginForm.onChallengeRequired` — provide it only if you want to render `ChallengeView` outside the form (e.g., in a modal or a separate route). For most apps, omitting this prop is the right choice.
  </Note>
</ParamField>

### Signup Integration Example

<CodeGroup>
  ```tsx Next.js App Router theme={null}
  'use client'
  import { SignupForm } from 'ailita-library'
  import { useRouter } from 'next/navigation'

  export default function SignupPage() {
    const router = useRouter()

    return (
      <SignupForm
        onSuccess={() => router.push('/dashboard')}
        onLoginClick={() => router.push('/login')}
      />
    )
  }
  ```

  ```tsx React Router theme={null}
  import { SignupForm } from 'ailita-library'
  import { useNavigate } from 'react-router-dom'

  export default function SignupPage() {
    const navigate = useNavigate()

    return (
      <SignupForm
        onSuccess={() => navigate('/dashboard')}
        onLoginClick={() => navigate('/login')}
      />
    )
  }
  ```
</CodeGroup>

***

## Forgot Password Flow

### How It Works

<Steps>
  <Step title="User enters email">
    `ForgotPasswordForm` collects the user's email address and calls the forgot-password API. The form is a single email field with a submit button.
  </Step>

  <Step title="Email OTP verification">
    The backend sends a 6-digit code to the provided email address. `ForgotPasswordForm` transitions to a verification screen and renders an inline `ChallengeView` for OTP entry.

    **Security behavior:** If the email address does not exist in the system, the API returns 404 — but the form still advances to the verification screen and shows: "If the email exists, we sent a code." This prevents email enumeration attacks. Developers must not override this behavior by adding a custom "email not found" error message.
  </Step>

  <Step title="Set new password">
    After OTP verification, the form transitions to a new password screen. The user enters a new password (minimum 8 characters, must contain at least one letter and one number) and a confirmation field. Mismatched passwords are validated client-side before the API call.
  </Step>

  <Step title="Password updated">
    A success confirmation screen is shown with a "Go to login" button. The `onSuccess()` callback fires at this point.
  </Step>
</Steps>

### allowPasswordRecovery

<Note>
  If the merchant has `allowPasswordRecovery` set to `false`, `ForgotPasswordForm` renders only a message: "Forgot your password? Please contact your administrator." with a link back to login. The forgot-password API is never called. This setting is read from the discovery response automatically — you do not check it manually. See [Provider Setup](/ailita/provider-setup) for details on merchant configuration.
</Note>

### ForgotPasswordForm Props

<ParamField body="onSuccess" type="() => void">
  Optional. Fires after the password has been successfully reset. Use this to navigate the user to the login page or display a global success notification.
</ParamField>

<ParamField body="onLoginClick" type="() => void">
  Optional. Fires when the user clicks "Back to login" on any step of the flow. Wire this to your login page route.
</ParamField>

### Forgot Password Integration Example

<CodeGroup>
  ```tsx Next.js App Router theme={null}
  'use client'
  import { ForgotPasswordForm } from 'ailita-library'
  import { useRouter } from 'next/navigation'

  export default function ForgotPasswordPage() {
    const router = useRouter()

    return (
      <ForgotPasswordForm
        onSuccess={() => router.push('/login')}
        onLoginClick={() => router.push('/login')}
      />
    )
  }
  ```

  ```tsx React Router theme={null}
  import { ForgotPasswordForm } from 'ailita-library'
  import { useNavigate } from 'react-router-dom'

  export default function ForgotPasswordPage() {
    const navigate = useNavigate()

    return (
      <ForgotPasswordForm
        onSuccess={() => navigate('/login')}
        onLoginClick={() => navigate('/login')}
      />
    )
  }
  ```
</CodeGroup>

***

## Wiring All Auth Pages Together

The recommended routing structure for a complete authentication surface:

```
/login           → <LoginForm onSignupClick={→/signup} onForgotPasswordClick={→/forgot-password} />
/signup          → <SignupForm onLoginClick={→/login} />
/forgot-password → <ForgotPasswordForm onLoginClick={→/login} />
```

<Note>
  All three components are self-contained. They manage their own internal state machines and render `ChallengeView` inline when needed. You only need to wire the navigation callbacks — no state lifting required.
</Note>

## Next Steps

<Card title="Auth Flows" icon="key" href="/ailita/auth-flows">
  Deep dive into the login state machine, challenge handling, and TOTP verification.
</Card>

<Card title="Hooks: useAuth & useUser" icon="code" href="/ailita/hooks">
  Access auth state, user data, and trigger auth actions programmatically.
</Card>
