# `AuthorizedUserInviteController` plan

## Scope
- **Controller**: `app/Http/Controllers/Api/Parents/AuthorizedUserInviteController.php`
- **Purpose**: public invite confirmation + password setup for “authorized users” invited by a parent.
- **Primary dependency**: `App\Services\Parents\AuthorizedUsersManagementService`

## Routes
- `GET /api/confirm_authorized_user?token=...` → `confirm`
- `GET /api/set_authorized_user_password/{authorizedUserId}?token=...` → `setPasswordForm`
- `POST /api/set_authorized_user_password/{authorizedUserId}` → `savePassword`
  - Path constraint: `{authorizedUserId}` is numeric

## Authentication & authorization
- These endpoints are **public** and rely on **invite tokens** for authorization.
- Redirects are protected via an allowlist check (`isTrustedRedirectUrl()`).

## Endpoint behavior
### `confirm`
- Input:
  - Query param `token` (string)
- Calls `AuthorizedUsersManagementService::confirmEmailClick($token)` and expects `redirect_url`.
- Output:
  - If request expects JSON: `{ message:"Confirmed.", redirect_url }`
  - Otherwise redirects the browser to `redirect_url` via `redirect()->away(...)`
- Errors:
  - Invalid token → `400` (JSON or minimal HTML page)
  - Untrusted redirect URL → `400` JSON `{ message:"Invalid redirect URL." }`

### `setPasswordForm`
- Input:
  - Route param `authorizedUserId`
  - Query param `token`
- Calls `AuthorizedUsersManagementService::findActiveSetupRow($authorizedUserId, $token)`.
- Output:
  - JSON mode: `{ message:"OK", user_id, token }`
  - HTML mode: instructional HTML (no actual password form UI)
- Errors:
  - Invalid/expired link → `400` (JSON or plain text)

### `savePassword`
- Input (JSON or form):
  - `password` (required; min 8; must include upper/lower/number/special)
  - `password_confirmation` or `password_confirm` (one required; must match `password`)
  - `user_id` (required int) — expected to match the authorized user’s owning parent id
  - `token` (required string)
- Calls `AuthorizedUsersManagementService::setAuthorizedUserPassword(...)`.
- Output:
  - Success: `{ message:"Password has been successfully set." }`
- Errors:
  - Validation → `422` with `{ message, errors }`
  - Invalid token / mismatch / expired setup row → `400` `{ message }`

## Security notes
- **Redirect allowlist**: only hosts matching `app.url`, `app.frontend_url`, or `services.frontend.url`.
- **Password policy** is enforced at the API level via regex rules.

## Test plan (feature)
- `confirm`
  - Invalid token → 400 JSON/HTML depending on `Accept`.
  - Valid token but redirect host not allowlisted → 400.
  - Valid token → JSON includes redirect_url; non-JSON issues redirect.
- `setPasswordForm`
  - Invalid token/id → 400.
  - Valid token/id → returns JSON payload or HTML string.
- `savePassword`
  - Weak password / missing confirm → 422.
  - Token mismatch/expired → 400.
  - Success → 200 and password is set (can authenticate as that authorized user).

