# Forgot password flow (email OTP)

Two-step password reset. OTP is sent **by email only** (no SMS).

## Summary

| Step | UI | Endpoint |
|------|-----|----------|
| 1 | Enter registered email | `POST /auth/forgot-password` |
| 2 | Enter OTP + new password | `POST /auth/reset-password` |

After reset, the user must log in again with the new password. All existing API tokens for that user are revoked.

---

## Base URL

```
{NEXT_PUBLIC_API_URL}/auth/...
```

Default local: `http://localhost:8000/api/v1/auth/...`

**Headers (both steps):**

```http
Content-Type: application/json
Accept: application/json
```

No `Authorization` header required.

---

## Step 1 — Request reset OTP

**`POST /auth/forgot-password`**

### Request body

```json
{
  "email": "john@example.com"
}
```

| Field | Type | Required | Rules |
|-------|------|----------|-------|
| `email` | string | yes | Valid email, max 191, **must exist** in `users.email` |

### Success `200`

```json
{
  "message": "Password reset OTP sent to email successfully",
  "email": "john@example.com"
}
```

OTP is valid for **10 minutes**.

### Errors

| Status | When |
|--------|------|
| `422` | Email not registered or invalid format |

**422 example:**

```json
{
  "message": "The selected email is invalid.",
  "errors": {
    "email": ["The selected email is invalid."]
  }
}
```

---

## Step 2 — Reset password

**`POST /auth/reset-password`**

### Request body

```json
{
  "email": "john@example.com",
  "otp": "123456",
  "newPassword": "newsecret123"
}
```

| Field | Type | Required | Rules |
|-------|------|----------|-------|
| `email` | string | yes | Same email used in step 1 |
| `otp` | string | yes | 6-digit code from email |
| `newPassword` | string | yes | Min **6** characters |

### Success `200`

```json
{
  "message": "Password reset successfully"
}
```

Redirect user to login. Do not expect an `accessToken` from this endpoint.

### Errors

| Status | Body |
|--------|------|
| `400` | `{ "message": "Invalid or expired OTP" }` |
| `404` | `{ "message": "User not found" }` |
| `422` | Validation errors (password too short, unknown email) |

---

## TypeScript types

```typescript
export interface ForgotPasswordRequest {
  email: string;
}

export interface ForgotPasswordResponse {
  message: string;
  email: string;
}

export interface ResetPasswordRequest {
  email: string;
  otp: string;
  newPassword: string;
}

export interface ResetPasswordResponse {
  message: string;
}
```

---

## Example UI flow

```typescript
// Step 1 — forgot password screen
await api.post("/auth/forgot-password", { email });
// → show OTP + new password form, keep email in state

// Step 2 — reset screen
await api.post("/auth/reset-password", {
  email,
  otp,
  newPassword,
});
// → toast success, navigate to /login
```

---

## Example axios sequence

```typescript
const baseURL = process.env.NEXT_PUBLIC_API_URL ?? "http://localhost:8000/api/v1";
const email = "john@example.com";

await axios.post(`${baseURL}/auth/forgot-password`, { email });

await axios.post(`${baseURL}/auth/reset-password`, {
  email,
  otp: "123456",
  newPassword: "newsecret123",
});
```

---

## Local development

When `APP_ENV=local`, OTP is always **`123456`** (same as signup).

---

## Security notes

- OTP cache is keyed by email and cleared after successful reset.
- All Sanctum tokens for the user are deleted on reset (forces re-login everywhere).
- Use the same email on both steps; OTP must match the latest forgot-password request for that email.

---

## Login after reset

**`POST /auth/user/login`**

```json
{
  "email": "john@example.com",
  "password": "newsecret123"
}
```
