Skip to content

[haxcms-elements] Store request tokens returned by login, refresh and connection-test - #882

Merged
btopro merged 1 commit into
masterfrom
security/session-request-tokens
Oct 19, 2026
Merged

btopro merged 1 commit into
masterfrom
security/session-request-tokens

Conversation

@btopro

@btopro btopro commented Oct 19, 2026 •

Copy link
Copy Markdown
Member

Follow-up to the session-hardening PRs (haxtheweb/haxcms-nodejs#71, haxtheweb/haxcms-php#655). This is step 1 of 2 for turning on security.requireSessionForRequestTokens.

Why

The backends can now leave siteToken / userToken out of connection-settings for anonymous page loads. Instead, login, refresh and connection-test responses return them. The editor loads connection-settings once, before login. If it doesn't pick the tokens up from those responses, the API registries drop all auth headers on token-protected calls and in-page login loops (401 → "Auth loop detected").

What changes

File Change
haxcms-elements/lib/core/utils/session-request-tokens.js (new) Reads tokens from a response (top-level or { data }). Writes them into appSettings in every shape the editor reads: userToken / siteToken, getUserDataHeaders[userTokenHeader], and appStore.headers['X-HAXCMS-Site-Token']. Nested objects are replaced, never mutated. A missing token never clears an existing one.
jwt-login/jwt-login.js After a successful login or refresh, re-broadcasts any tokens as jwt-login-session-tokens ({ userToken?, siteToken?, context }). It fires before the jwt changes, so a refresh retry already has the tokens. Nothing fires when neither token is present, or for logout.
app-hax/lib/v2/AppHaxBackendAPI.js (dashboard) Applies tokens from that event and from authenticated connection-test responses to globalThis.appSettings, store.appSettings and the system API registry.
haxcms-elements/lib/core/backends/haxcms-backend-nodejs.js / -php.js (site editor) Same as the dashboard, plus the site API registry. The site registry is updated synchronously so a refresh retry can't race it.

It works against backends in either mode. Where connection-settings still sends tokens, the responses carry the same values, so merging this changes nothing for today's deployments.

Tests

  • New: haxcms-elements/test/session-request-tokens.test.js, covering extraction shapes, every write target, no mutation, no clearing, and no-change detection.
  • jwt-login: the event on login, the enveloped shape, no event without tokens or on logout, and tokens arrive before the refresh retry runs.
  • app-hax backend API: connection-test tokens land in this.appSettings, store.appSettings, globalThis.appSettings and the registry. A failed connection-test applies nothing. The event handler works, and the no-token case is a no-op.

Local runs (web-test-runner, Chromium):

Suite Result
jwt-login 41/41
haxcms-elements (new file + site registry + demo backend) 59/59
app-hax 736/736

End-to-end with the backend flag on: I copied these files into a scratch copy of haxcms-nodejs's src/public/build and ran haxcms-nodejs's npm run test:e2e against the companion backend PR, where requireSessionForRequestTokens defaults to on. Results are in the companion PR.

Merge order

  1. This PR. Release it, then refresh the front-end build in both backends (their build/ folders; the managed packaging step, not by hand).
  2. [haxcms-nodejs] Login returns siteToken with the JWT haxcms-nodejs#79 and [haxcms-php] Login returns siteToken with the JWT haxcms-php#662. These turn the flag on by default and make login return siteToken too. They must land after step 1's build is in each backend.

jwt-login.test.js and app-hax-backend-api.test.js were already not Prettier-clean on master. I left their existing formatting alone so the diff only shows the new tests.

https://claude.ai/code/session_013J4JEf3WfrBgaePbuRC7uF


Generated by Claude Code

HAXcms backends (haxcms-nodejs#71, haxcms-php#655) can omit userToken /
siteToken from connection-settings for anonymous page loads
(security.requireSessionForRequestTokens) and instead return them on
successful login, refresh and connection-test responses. The editor loads
connection-settings once, before login, so it has to pick them up from those
responses or token-protected calls drop all auth headers and login loops.

- haxcms-elements/lib/core/utils/session-request-tokens.js: extract tokens from
  a response (top-level or { data }) and write them into appSettings in every
  shape the editor reads: userToken / siteToken, getUserDataHeaders, and
  appStore.headers. Nested objects are replaced, never mutated; missing
  tokens never clear existing ones.
- jwt-login: after a successful login or refresh, re-broadcast any tokens in
  the response as `jwt-login-session-tokens` ({ userToken?, siteToken?,
  context }), dispatched before the jwt changes so refresh retries already
  have them.
- AppHaxBackendAPI (dashboard) and haxcms-backend-nodejs / -php (site
  editor): apply tokens from that event and from authenticated
  connection-test responses to globalThis.appSettings, store.appSettings and
  the system / site API registries.
- tests: helper unit tests, jwt-login event + ordering, AppHaxBackendAPI
  connection-test and event handling.

Works with backends in either mode: when connection-settings still sends the
tokens, the responses carry the same values.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013J4JEf3WfrBgaePbuRC7uF
Copilot AI balanced review requested due to automatic review settings October 19, 2026 17:28
@vercel

vercel Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
webcomponents Ready Ready Preview Oct 19, 2026 5:29pm UTC

Request Review

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing.

@btopro
btopro merged commit ab0e7e7 into master Oct 19, 2026
9 checks passed
@btopro
btopro deleted the security/session-request-tokens branch October 19, 2026 18:07
@github-actions github-actions Bot locked and limited conversation to collaborators Oct 19, 2026

This branch was successfully deployed

1 active deployment
Preview — bb7b00f2 Deployed Oct 19, 2026 by vercel[bot]
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants