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

# Authentication pattern

> Sign in, sign up and password reset — layout, validation, error handling and the accessibility requirements each screen carries.

Consistent, accessible authentication screens. This page covers the interface pattern; it
deliberately does not specify an identity provider, which is an application-level decision.

## Sign in

A centred card on a muted background.

```tsx theme={null}
<div className="flex min-h-screen items-center justify-center bg-muted px-4">
  <Card className="w-full max-w-sm">
    <CardHeader className="space-y-2 text-center">
      <CardTitle className="text-xl">Sign in</CardTitle>
      <p className="text-sm text-muted-foreground">
        Enter your email to sign in to your account
      </p>
    </CardHeader>
    <CardContent>
      <form className="space-y-4">
        <Field>
          <FieldLabel>Email address</FieldLabel>
          <Input type="email" placeholder="you@example.com" autoComplete="email" />
        </Field>
        <Field>
          <div className="flex items-center justify-between">
            <FieldLabel>Password</FieldLabel>
            <a href="/forgot-password" className="text-xs text-muted-foreground hover:text-foreground">
              Forgot password?
            </a>
          </div>
          <Input type="password" autoComplete="current-password" />
        </Field>
        <Button type="submit" className="w-full">Sign in</Button>
      </form>

      <Separator className="my-6" />

      <p className="text-center text-sm text-muted-foreground">
        Do not have an account?{" "}
        <a href="/signup" className="font-medium text-foreground underline underline-offset-2">
          Sign up
        </a>
      </p>
    </CardContent>
  </Card>
</div>
```

The registry ships `mzizi-auth-card` and `mzizi-auth-layout` if you would rather not compose
this yourself.

## Sign up

The same layout with a name field and a stated password requirement.

```tsx theme={null}
<form className="space-y-4">
  <Field>
    <FieldLabel>Full name</FieldLabel>
    <Input type="text" autoComplete="name" />
  </Field>
  <Field>
    <FieldLabel>Email address</FieldLabel>
    <Input type="email" placeholder="you@example.com" autoComplete="email" />
  </Field>
  <Field>
    <FieldLabel>Password</FieldLabel>
    <Input type="password" autoComplete="new-password" />
    <FieldDescription>At least 8 characters</FieldDescription>
  </Field>
  <Button type="submit" className="w-full">Create account</Button>
</form>
```

### One name field

Use a single **Full name** field. Do not split into first and last, and do not validate its
length. See [inclusive language](/content/inclusive-language) for why.

## Validation

```tsx theme={null}
const signInSchema = z.object({
  email: z.string().email("Enter a valid email address"),
  password: z.string().min(1, "Password is required"),
})

const signUpSchema = z.object({
  name: z.string().min(1, "Name is required"),
  email: z.string().email("Enter a valid email address"),
  password: z.string().min(8, "Password must be at least 8 characters"),
})
```

Show errors inline with `FormMessage`.

## Error handling

| Situation | Message |
| - | - |
| Wrong credentials | "Incorrect email or password. Try again or reset your password." |
| Account locked | "Too many attempts. Your account is locked for 15 minutes." |
| Email not verified | "Check your email for a verification link." |
| Network error | "Could not connect. Check your internet and try again." |

<Warning>
  **Never reveal whether an email exists.** "Incorrect email or password" for a failed sign-in;
  the same confirmation screen on password reset whether or not the address is registered.
  Distinguishing the two turns a sign-in form into an account-enumeration endpoint.
</Warning>

## Accessibility

* Every input has an associated label.
* `autoComplete` on every field, so a password manager can fill it.
* The form is fully keyboard-navigable.
* Errors are announced — use `aria-live`.
* The submit button shows its loading state.

```tsx theme={null}
<Button className="w-full" disabled={isSubmitting}>
  {isSubmitting ? (
    <>
      <Spinner className="size-4" />
      Signing in…
    </>
  ) : (
    "Sign in"
  )}
</Button>
```

## Sessions

* Keep session tokens in HTTP-only cookies, not `localStorage` — a token a script can read is
  a token an injected script can exfiltrate.
* Refresh tokens rather than forcing frequent re-authentication.
* Put a clear sign-out action in the user menu.
* Confirm before signing out of all devices.

## Password reset

1. The reader selects "Forgot password?" on the sign-in screen.
2. They enter an email address.
3. The system sends a reset link — and confirms it did, without saying whether the address was
   registered.
4. They follow the link and set a new password.
5. They are returned to sign in.

Every step uses the same centred card, so the flow reads as one thing rather than four.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.