> ## 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.

# Authentication: Sessions and CSRF Tokens Explained

> Learn how the Ecommerce API uses session cookies and CSRF tokens to authenticate requests, and how to log in, log out, and manage sessions.

The Ecommerce API authenticates requests using server-side sessions with an opaque `session` cookie. Rather than long-lived API keys, each login or registration creates a new session. Write operations — any POST, PATCH, or DELETE — additionally require a short-lived CSRF token to prevent cross-site request forgery. This two-layer approach means your credentials never travel in a header or URL, and every sensitive action is explicitly authorized.

## How Authentication Works

When you log in or register, the server issues an HttpOnly `session` cookie with `SameSite=Lax`. Because the cookie is HttpOnly, JavaScript running in the browser cannot read it — only the browser itself forwards it automatically on same-origin requests. The `SameSite=Lax` policy prevents the cookie from being sent on cross-site subresource requests while still allowing top-level navigations.

Key properties of the `session` cookie:

* **HttpOnly** — not accessible via `document.cookie`; protects against XSS token theft
* **SameSite=Lax** — sent on same-site requests and top-level cross-site navigations, blocked on cross-site subrequests
* **Opaque** — the cookie value is a random token; the server looks up the session record in the database on every request
* **Revocable** — call `DELETE /auth/session` (current session) or `DELETE /auth/sessions/{id}` (any session) to invalidate immediately

The session remains valid until it expires naturally or you log out. Suspended or deleted accounts cannot obtain new sessions, and existing sessions for those accounts are rejected with `401 Unauthorized`.

## Getting a Session

Call `POST /auth/login` with your email and password to authenticate. On success the server sets the `session` cookie and returns your `public_id` and `email_verified` status.

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

  ```javascript JavaScript (fetch) theme={null}
  const response = await fetch('https://api.example.com/api/v1/auth/login', {
    method: 'POST',
    credentials: 'include',
    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()
  response = session.post(
      'https://api.example.com/api/v1/auth/login',
      json={'email': 'jane@example.com', 'password': 'S3cure!Pass'},
  )
  data = response.json()
  # session cookie is stored automatically in session.cookies
  ```
</CodeGroup>

**Successful response (`200 OK`):**

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

To create a brand-new account instead, call `POST /auth/register` with the same fields plus `first_name`, `last_name`, and `phone_number` (E.164 format). Registration also sets the session cookie and queues a 24-hour verification email.

<Warning>
  Cookie-based authentication requires your HTTP client to send credentials with every request. In the browser, always include `credentials: 'include'` in your `fetch` calls. In `axios`, set `withCredentials: true`. Without this flag the browser silently omits the session cookie and you receive a `401` on every authenticated endpoint.
</Warning>

## CSRF Protection

Every state-changing request — any `POST`, `PATCH`, or `DELETE` — must include a valid CSRF token in the `x-csrf-token` header. The token is bound to your current session, so you must have an active session before fetching one.

**Step 1 — Fetch a token:**

<CodeGroup>
  ```bash cURL theme={null}
  curl -b cookies.txt https://api.example.com/api/v1/auth/csrf-token
  ```

  ```javascript JavaScript (fetch) theme={null}
  const res = await fetch('https://api.example.com/api/v1/auth/csrf-token', {
    credentials: 'include',
  });
  const { data } = await res.json();
  const csrfToken = data.csrf_token;
  ```

  ```python Python (requests) theme={null}
  resp = session.get('https://api.example.com/api/v1/auth/csrf-token')
  csrf_token = resp.json()['data']['csrf_token']
  ```
</CodeGroup>

**Token response (`200 OK`):**

```json theme={null}
{
  "success": true,
  "data": {
    "csrf_token": "csrf_abc123"
  }
}
```

**Step 2 — Use the token in your write request:**

<CodeGroup>
  ```bash cURL theme={null}
  curl -b cookies.txt -X POST https://api.example.com/api/v1/cart/items \
    -H "Content-Type: application/json" \
    -H "x-csrf-token: csrf_abc123" \
    -d '{"variant_public_id": "var_01H", "quantity": 1}'
  ```

  ```javascript JavaScript (fetch) theme={null}
  await fetch('https://api.example.com/api/v1/cart/items', {
    method: 'POST',
    credentials: 'include',
    headers: {
      'Content-Type': 'application/json',
      'x-csrf-token': csrfToken,
    },
    body: JSON.stringify({ variant_public_id: 'var_01H', quantity: 1 }),
  });
  ```

  ```python Python (requests) theme={null}
  session.post(
      'https://api.example.com/api/v1/cart/items',
      json={'variant_public_id': 'var_01H', 'quantity': 1},
      headers={'x-csrf-token': csrf_token},
  )
  ```
</CodeGroup>

The CSRF token is also set as an HttpOnly cookie by the server alongside the JSON body response — the server validates it by comparing the cookie value with the `x-csrf-token` header value (double-submit cookie pattern). A missing or mismatched token returns `403 Forbidden`.

<Tip>
  Always fetch a fresh CSRF token immediately before starting a write sequence — especially before checkout or account updates. Tokens can expire with the session, and reusing a stale token causes a `403` that interrupts your flow. A single token fetch at the start of each user action is the safest strategy.
</Tip>

## Session Management

The API gives you full visibility and control over all active sessions for your account.

| Endpoint                                    | Method | Description                                              |
| ------------------------------------------- | ------ | -------------------------------------------------------- |
| `GET /auth/session`                         | GET    | Returns the current session's details and basic profile  |
| `GET /auth/sessions`                        | GET    | Lists all active sessions for your account, newest first |
| `DELETE /auth/session`                      | DELETE | Logs out and revokes the current session                 |
| `DELETE /auth/sessions/{session_public_id}` | DELETE | Revokes a specific session by its public ID              |

Each session entry in the list includes a `public_id` (prefixed `ses_`), device and IP metadata, `created_at`, and `expires_at` timestamps in ISO 8601 UTC.

**List all active sessions:**

```bash theme={null}
curl -b cookies.txt https://api.example.com/api/v1/auth/sessions
```

**Revoke a specific session:**

```bash theme={null}
curl -b cookies.txt -c cookies.txt \
  -H "x-csrf-token: csrf_abc123" \
  -X DELETE https://api.example.com/api/v1/auth/sessions/ses_01H
```

<Info>
  Revoking your **current** session via `DELETE /auth/sessions/{id}` clears the session cookie immediately — the same effect as calling `DELETE /auth/session`. Revoking another session (e.g., from a different device) does not affect your current session or cookie.
</Info>
