Task: Integrate MODX frontend sessions into the haih-agent auth context
Integrate MODX frontend sessions into the haih-agent auth context
Teach the new Kilfor frontend to identify the current user directly via the existing MODX session without depending on a legacy HTTP endpoint.
Context
Kilfor user sessions are currently stored and managed by MODX. The new frontend based on haih-agent already implements part of the application logic independently, so it periodically needs detailed information about the currently authenticated user.
MODX has an internal PHP API for working with the current user inside the MODX runtime, but there is no out-of-the-box standard external HTTP endpoint at the current user level for the frontend context. modSociety has its own endpoint for retrieving the user, but the new frontend must not depend on this legacy component.
Goal
Implement an infrastructure layer in haih-agent capable of determining the user authorized in a given frontend context (web or another) based on the existing MODX session cookie, and providing normalized user data to the application code of the new frontend.
What to Research and Implement
- Understand the actual frontend session storage format in the used version of MODX and on Kilfor.
- Determine how to retrieve the user for a specific context key using the session ID and
modx_sessiondata. - Correctly parse PHP session serialization without relying on regex hacks.
- Retrieve necessary user data from
modUser,modUserProfile, and project relations. - Make the MODX-specific implementation a separate adapter/provider so that application code works with the
currentUserabstraction rather than knowing the MODX session structure. - Do not hardcode
webinto the low-level parser: the context key should be set via configuration or by the calling auth layer. - Handle session expiration/invalidity and lack of authorization in the requested context.
- Do not port the entire MODX ACL/security runtime without a specific need; at the first stage, the task is to reliably identify the user and their data.
- Provide for the possibility of a different session storage/handler in the future, without tightly coupling all auth code to SQL queries against
modx_session. - Cover the parser and user identification with fixture/integration tests using real MODX frontend session examples.
Expected Result
A normalized current user for the specified frontend context, retrieved directly from the existing MODX session, is available in the haih-agent GraphQL/request context. This eliminates the need for a separate request to the legacy modSociety endpoint or a MODX bootstrap on every new frontend request.
Ворклоги
Summary of Work
The task of reading existing MODX frontend sessions on the haih-agent side has been practically resolved and can be considered complete.
What Has Been Tested
On the new frontend side, it was possible to directly read MODX session data without a MODX bootstrap and without calling the legacy modSociety endpoint. This confirms the architectural feasibility of using MODX as the current session store, while parsing and further data processing are handled within haih-agent.
It also turned out that the main technical issue was not reading the session record from the database, but rather deserializing its PHP session payload in Node.js.
The Issue with php-serialize
php-serialize does not solve the problem directly because the MODX/PHP session in the format used is not simply the result of serialize($_SESSION). Therefore, the library is not suitable as a ready-made session decoder for the current case.
Using php-session-unserialize
To parse the session, the php-session-unserialize package was used. It correctly reads the PHP session format itself, but a library implementation quirk was discovered: PHP associative arrays inside readArray() are always created as JavaScript Arrays.
Essentially, the library does the following:
const resultArray = []
resultArray[key] = value
If a PHP array contains a string key, such as mgr, the result in JavaScript is an array with a named property (arr.mgr = ...). Such data is visible in console.log, but JSON.stringify and GraphQL only serialize indexed array elements, so the named properties are lost.
Practical example: a MODX session value like
modx.user.0.resourceGroups => { mgr: [] }
looked correct in the logs after initial parsing, but via GraphQL it turned into:
"modx.user.0.resourceGroups": []
Implemented Workaround
A recursive normalization of the result was added after unserialize():
function convertArraysToObjects(obj: unknown): unknown {
if (Array.isArray(obj)) {
const keys = Object.keys(obj)
const hasStringKeys = keys.some((k) => isNaN(Number(k)))
if (hasStringKeys) {
const result: Record<string, unknown> = {}
for (const key of keys) {
result[key] = convertArraysToObjects(
(obj as unknown as Record<string, unknown>)[key],
)
}
return result
}
return obj.map(convertArraysToObjects)
}
if (obj && typeof obj === 'object') {
const result: Record<string, unknown> = {}
for (const [key, value] of Object.entries(obj)) {
result[key] = convertArraysToObjects(value)
}
return result
}
return obj
}
After this, PHP associative arrays with named keys are converted to regular JS objects and pass correctly through JSON/GraphQL.
Result
After normalization, MODX session data is read correctly, including nested structures. In particular, branches such as the following are successfully retrieved:
{
"modx.user.0.resourceGroups": {
"mgr": []
},
"modx.user.0.attributes": {
"web": {
"modAccessContext": {
"web": [
{
"principal": 0,
"authority": "0",
"policy": {
"load": true,
"formit": true,
"formit_encryptions": false
}
}
]
}
}
}
}
Data for other users/contexts, such as modx.user.1.attributes and ACL structures with a large set of manager permissions, are also visible in the session. This means the session payload is now fully available without losses during GraphQL serialization.
Limitations of the Current Solution
Theoretically, the current converter might ambiguously transform a PHP array with mixed numeric and string keys: if at least one string key is present, the entire JS Array turns into an Object. For standard MODX session structures, this is currently not critical; real data required by the project arrives correctly after normalization.
Therefore, at this stage, there is no need to write a custom PHP session parser or fork the library. If a real MODX session payload that the current scheme parses incorrectly is encountered later, it can be spun off into a separate technical task.
Scope of Completed Task
The goal of this task was specifically to prove the feasibility of reading and correctly deserializing an existing MODX frontend session on the haih-agent side. This goal has been achieved.
The logic for determining the specific current user based on session contents, selecting the required frontend context, retrieving additional user data, and subsequently building the auth/currentUser API constitutes the next application layer and, if necessary, should be structured separately.