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

# Consumer Authentication Flow

> How consumer login, contact capture, OTP verification, and token creation work in API 2.0.

Consumer authentication is identity-based, not password-based. A consumer starts with the same identifiers used by the current portal: last name, date of birth, and last four SSN digits.

## Current App Behavior

The current Laravel portal signs in a `Consumer` record with the `consumer` guard. The login screen checks last name, DOB, and last four SSN against the stored consumer identity. If the browser is trusted, the user can enter without another OTP. Otherwise the app stores a pending OTP session and moves the user through contact capture or OTP verification screens.

If no matching consumer is found, the app asks the user to confirm account creation. On confirmation, it creates the consumer profile/account path and starts the same OTP verification flow.

## API 2.0 Behavior

The backend API keeps the same user-facing flow. Normal authenticated API calls use bearer tokens. The trusted-device cookie is only used during a future identity login so the same browser can skip OTP after a previous successful OTP verification.

| Step                | Endpoint                    | What the client should do                                                                                                                                                                                         |
| ------------------- | --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Match identity      | `POST /auth/login`          | Send last name, DOB, last four SSN, and reCAPTCHA. Store `flow_token` if matched, `attempt_token` if not matched, or `meta.access_token` and `meta.refresh_token` if the backend accepts a trusted-device cookie. |
| Confirm new profile | `POST /auth/confirm-create` | Use `attempt_token` only after the user confirms the no-match path. Store the returned `flow_token`.                                                                                                              |
| Add first contact   | `POST /auth/contact`        | Required when login returns `requires_contact_input: true`. Send email or US mobile number.                                                                                                                       |
| Resend OTP          | `POST /auth/otp/resend`     | Use the active `flow_token`. A flow can only resend after the cooldown window.                                                                                                                                    |
| Verify OTP          | `POST /auth/otp/verify`     | Send `flow_token`, `otp`, optional `device_name`, and `remember_device: true` when the user trusts this browser. Store `meta.access_token` and `meta.refresh_token`.                                              |
| Refresh token       | `POST /auth/refresh`        | Send `refresh_token` when the frontend is ready to rotate tokens. The backend returns a replacement access/refresh pair.                                                                                          |
| Use API             | Authenticated endpoints     | Send `Authorization: Bearer <consumer-token>`.                                                                                                                                                                    |

The access token belongs to the `ConsumerProfile`, not a single account row. That lets the authenticated consumer profile list and open the accounts it owns.

## Login Responses

`POST /auth/login` has four successful branches:

| Branch                                   | Response                                                      | Frontend behavior                                            |
| ---------------------------------------- | ------------------------------------------------------------- | ------------------------------------------------------------ |
| Existing profile with OTP channel        | `matched: true`, `otp_sent: true`, `flow_token`               | Show the OTP screen.                                         |
| Existing profile needs first contact     | `matched: true`, `requires_contact_input: true`, `flow_token` | Show email/mobile capture, then send OTP.                    |
| No matching profile                      | `matched: false`, `attempt_token`                             | Ask the consumer to confirm account creation.                |
| Existing profile trusted on this browser | `matched: true`, `trusted_device: true`, token `meta`         | Store/use the bearer token and refresh token, then skip OTP. |

`POST /auth/login` and `POST /auth/otp/verify` do not return the consumer profile payload. After any branch returns `meta.access_token`, the frontend can call the authenticated profile endpoint if it needs profile details.

For browser frontends, `POST /auth/otp/verify` and `POST /auth/login` must include credentials. OTP verification needs credentials so the browser accepts the `Set-Cookie` response, and login needs credentials so the browser sends the trusted-device cookie back. With `fetch`, use `credentials: "include"`. With Axios, use `withCredentials: true`.

## Guardrails

`attempt_token` and `flow_token` are short-lived and single-use after completion. OTP codes expire after the flow window, resend is rate-limited, and verification locks out after repeated failed attempts. Email OTPs are hashed before storage; mobile OTPs are verified through Twilio Verify.

Trusted-device cookies are HTTP-only and opaque to frontend JavaScript. The frontend should not read or build the cookie value. The backend sets it after a successful OTP verification with `remember_device: true`, stores only a server-side hash, and validates it on a future `POST /auth/login`.

For developer and controlled environment workflows, the backend may accept an OTP bypass according to server configuration: local accepts any six-digit OTP, and other environments can opt into a configured bypass code. Frontend code should still follow the normal OTP flow and treat bypass as an environment-only backend behavior.
