Skip to content

fix(auth): httpOnly cookie token architecture#124

Merged
biz87 merged 4 commits intobetafrom
dev/new-auth
Mar 1, 2026
Merged

fix(auth): httpOnly cookie token architecture#124
biz87 merged 4 commits intobetafrom
dev/new-auth

Conversation

@biz87
Copy link
Copy Markdown
Member

@biz87 biz87 commented Mar 1, 2026

Summary

  • Проблема: 4 независимых хранилища токена (localStorage, $_SESSION, ms3_customer_tokens, msCustomer.token) без синхронизации. Корзина не работает после логина — добавление идёт по одному токену, отображение по другому.
  • Решение: httpOnly cookie ms3_token как единственный источник правды. Токен устанавливается сервером, отправляется браузером автоматически, недоступен из JS.
  • Middleware injection ($_COOKIE → $_REQUEST) обеспечивает обратную совместимость — CartController, OrderController, AuthorizedCustomerTrait работают без изменений.

Changes

New

  • CookieHelper — управление httpOnly cookie, использует MODX session_cookie_* настройки
  • TokenService::resolveOrCreateToken() — единая цепочка разрешения токена (session → cookie → generate)
  • Customer::autoLoginCustomer() — привязка msCustomerToken к customer при автологине после первого заказа

Modified

  • TokenMiddleware — cookie injection в $_REQUEST, поддержка Authorization: Bearer, auto-create токена для первого визита
  • Login.php — использует существующий токен вместо создания нового, привязывает draft к customer
  • Register.php — аналогично Login + фикс формата response (token возвращает строку, не объект)
  • Logout.php — revoke всех API-токенов customer, генерация свежего анонимного токена (bin2hex(random_bytes(32))). Старая гостевая корзина теряется (security: старый токен инвалидирован)
  • 5 сниппетов — единый $tokenService->resolveOrCreateToken() вместо дублирующейся логики
  • JS (TokenManager, ApiClient, auth-forms) — убран localStorage, добавлен credentials: 'same-origin'
  • OrderDraftManagersortby('id', 'DESC') при поиске draft по customer_id, bindDraftToCustomer() с фильтром по context

Not modified (backward compat via middleware)

  • CartController (6 мест с $_REQUEST)
  • OrderController (14 мест с $_REQUEST)
  • AuthorizedCustomerTrait

⚠️ Breaking changes

Register.php response format

До:

{
  "token": { "token": "abc123...", "expires_at": "2026-03-09 12:00:00" }
}

После:

{
  "token": "abc123...",
  "expires_at": "2026-03-09 12:00:00"
}

Поле token теперь возвращает строку вместо объекта. Поле expires_at вынесено на верхний уровень. Кастомные темы/интеграции, обращающиеся к result.object.token.token, потребуют обновления.

Test plan

  • Гость: добавление в корзину → cookie ms3_token появляется (httpOnly=true)
  • Гость: оформление заказа → customer создаётся, корзина сохраняется
  • Логин: гостевая корзина сохраняется после авторизации
  • Регистрация с autoLogin: корзина сохраняется
  • Логаут: старый токен revoked, создаётся новый анонимный токен, корзина начинается заново
  • Обновление страницы: корзина не теряется
  • Протухание PHP-сессии: cookie восстанавливает сессию
  • localStorage: очищается, не используется
  • DevTools: ms3_token нет в URL-параметрах запросов

🤖 Generated with Claude Code

TolkIT-team and others added 4 commits March 2, 2026 01:36
Replace 4 independent token storages (localStorage, $_SESSION,
ms3_customer_tokens, msCustomer.token) with single httpOnly cookie
as source of truth. Fixes cart desync after login/session expiry.

Key changes:
- CookieHelper: httpOnly cookie ms3_token using MODX session_cookie_* settings
- TokenService::resolveOrCreateToken(): unified token resolution chain
  (session → cookie → generate new)
- TokenMiddleware: cookie injection into $_REQUEST for backward compat
  with all controllers, Authorization: Bearer support
- Login/Register: reuse existing token instead of creating new one,
  bind draft order to customer — guest cart preserved on login
- Logout: detach customer from token, keep cookie for guest cart
- Snippets: unified token resolution via resolveOrCreateToken()
- JS: remove localStorage usage, use credentials: 'same-origin'
- OrderDraftManager: add sortby('id', 'DESC') for deterministic
  draft selection with multiple drafts
- Customer::autoLoginCustomer(): bind msCustomerToken to customer
  and set cookie on auto-login after first order

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Review fixes:
- DRY: move bindDraftToCustomer() to OrderDraftManager, remove
  duplicates from Login.php and Register.php
- TTL: unify on ms3_customer_token_ttl (default 604800) everywhere,
  remove ms3_customer_api_token_ttl references
- Logout: generate fresh anonymous token instead of reusing old
  (potentially compromised) token string
- CookieHelper: add guard against duplicate Set-Cookie headers
  when cookie already has correct value
- ms3_customer.php: remove clearTokenCookie on redirect to login
  (was destroying guest cart cookie)
- TokenMiddleware: remove redundant cookie check in resolveToken()
  (cookie already injected into $_REQUEST), update docblock
- auth-forms.js: clean up dead comments
- Customer::autoLoginCustomer(): clarify $this->token fallback chain

Co-Authored-By: Claude Opus 4.6 <[email protected]>
- CookieHelper: fix sliding expiry — static flag now actually set after setcookie()
- TokenMiddleware: merge duplicate resolveToken() comments (steps 3-4 → step 3)
- OrderDraftManager: add $ctx parameter to bindDraftToCustomer() for consistency

Co-Authored-By: Claude Opus 4.6 <[email protected]>
- CookieHelper: bool $cookieSetInThisRequest → ?string $lastTokenSet
  Prevents duplicate Set-Cookie for same token, allows token change (Logout)
- clearTokenCookie() resets $lastTokenSet = null
- CHANGELOG: document PR #124 fix + Register.php breaking change

Co-Authored-By: Claude Opus 4.6 <[email protected]>
@biz87 biz87 merged commit e43962b into beta Mar 1, 2026
@Ibochkarev Ibochkarev deleted the dev/new-auth branch March 16, 2026 07:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants