> ## 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 `nyuchi-auth-card` and `nyuchi-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.
