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

# Log In with Email and Password via POST /auth/login

> Authenticate with email and password to receive a session cookie. Brute-force protection locks the account after 10 failed attempts for 15 minutes.

Logging in authenticates you with your email and password and sets an HttpOnly session cookie on the response. All subsequent authenticated API calls rely on that cookie being present. The endpoint also returns your account's email verification status so your UI can prompt for verification if needed.

## Endpoint

```http theme={null}
POST https://api.example.com/api/v1/auth/login
```

This endpoint is **public** — no existing session or CSRF token is required.

## Request Body

<ParamField body="email" type="string" required>
  The email address associated with your account.
</ParamField>

<ParamField body="password" type="string" required>
  Your account password.
</ParamField>

## Example Request

<CodeGroup>
  ```bash cURL theme={null}
  curl -i -X POST https://api.example.com/api/v1/auth/login \
    -H "Content-Type: application/json" \
    -c cookies.txt \
    -d '{
      "email": "jane@example.com",
      "password": "S3cure!Pass"
    }'
  ```

  ```js JavaScript (fetch) theme={null}
  const response = await fetch(
    "https://api.example.com/api/v1/auth/login",
    {
      method: "POST",
      credentials: "include",          // required for the session cookie
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        email: "jane@example.com",
        password: "S3cure!Pass",
      }),
    }
  );
  const data = await response.json();
  ```

  ```python Python (requests) theme={null}
  import requests

  session = requests.Session()
  resp = session.post(
      "https://api.example.com/api/v1/auth/login",
      json={
          "email": "jane@example.com",
          "password": "S3cure!Pass",
      },
  )
  # The session object now carries the session cookie automatically
  print(resp.json())
  ```
</CodeGroup>

## Success Response — `200 OK`

The session cookie is set and your account details are returned.

```json theme={null}
{
  "success": true,
  "data": {
    "public_id": "usr_01H",
    "email_verified": true
  }
}
```

<ResponseField name="success" type="boolean">
  Always `true` for successful responses.
</ResponseField>

<ResponseField name="data" type="object">
  <Expandable title="data fields">
    <ResponseField name="public_id" type="string">
      Opaque public identifier for your account, prefixed `usr_`. Use this to identify the logged-in user in your application.
    </ResponseField>

    <ResponseField name="email_verified" type="boolean">
      `true` if you have completed email verification, `false` otherwise. Some API features may require a verified email.
    </ResponseField>
  </Expandable>
</ResponseField>

<Warning>
  **Brute-force lockout:** After **10 consecutive failed login attempts** the account is locked for **15 minutes**. During the lockout period every attempt — including a correct password — returns `429 Too Many Requests`. Wait for the cooldown to expire before trying again. Do not implement automated retry loops that could trigger or extend the lockout.
</Warning>

## Error Responses

| Status                  | Meaning                   | When it occurs                                                                                                                                                                                                               |
| ----------------------- | ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `401 Unauthorized`      | Invalid credentials       | The email is not registered, the password is wrong, or the account combination could not be verified. The response deliberately avoids distinguishing between "email not found" and "wrong password" to prevent enumeration. |
| `403 Forbidden`         | Account not accessible    | The account has been **suspended** by an administrator or has been **deleted**. Contact support if you believe this is an error.                                                                                             |
| `429 Too Many Requests` | Rate limited / locked out | Either the per-IP rate limit was hit, or 10 failed attempts have triggered a 15-minute account lockout.                                                                                                                      |

### Example `401` Invalid Credentials

```json theme={null}
{
  "success": false,
  "error": {
    "code": "UNAUTHORIZED",
    "message": "invalid email or password"
  }
}
```

### Example `403` Suspended Account

```json theme={null}
{
  "success": false,
  "error": {
    "code": "FORBIDDEN",
    "message": "account is suspended"
  }
}
```

### Example `429` Lockout

```json theme={null}
{
  "success": false,
  "error": {
    "code": "TOO_MANY_REQUESTS",
    "message": "too many failed attempts, account locked for 15 minutes"
  }
}
```

## Next Steps

After a successful login, fetch a CSRF token before calling any state-changing endpoint:

<CardGroup cols={2}>
  <Card title="Get a CSRF Token" icon="shield-halved" href="/authentication">
    Required before any POST, PATCH, or DELETE request.
  </Card>

  <Card title="View Current Session" icon="circle-user" href="/api-reference/auth/logout">
    Call GET /auth/session to confirm your session is active.
  </Card>
</CardGroup>
