Security
GG_WEB_SOCKET_SECURITY_CHECK runs before any submitted data is used. It is not a filter the client can bypass, and most "my value never arrives" problems are really this method doing its job.
It checks eight things: the domain, the access rights for the page type, the user's authentication, redirects, whether the page is published, whether the triggered event is actually configured on the served page, the form constraints (required, type, regex, captcha), and finally it strips POST data that was not expected.
The rule that makes it safe
A client may only trigger an event that exists on the page it was served. The check re-reads the page's blocks server-side and looks for the event there. Nothing about the request is taken on trust: not the class name, not the function name.
Consequences you will meet in practice:
- A
call4DFunctionchosen freely from the client is refused. To call something arbitrary, put the event on a relay block that legitimately carries it. - Admin screens rendered from a stored template are a special case, and a narrow one: a single template is accepted, and only for a user who may edit the page. Otherwise any visitor could fire an admin screen's events from a public page.
The whitelist that silently deletes your fields
The check builds $vo_InputsExpected from the blocks actually in scope, then removes from $vo_POST.vt_FieldValue every key that is not in it.
Expected keys are the field names, the block names and, for a listbox, the derived ones: _selectedRows, _selectedDatas, _listboxUuidKey, _searchFields, _checkAll.
So a field the check does not recognise disappears with no message. Two ways to get there:
- the field has no
vt_FieldName: it is not in the whitelist, so it is stripped; - the field is outside the container named by
vt_SendAllObjectsOfBlocName: it was never collected in the first place.
The symptom is identical in both cases: the function runs, reports success, and saves nothing. Read the request body of /bweb/call-action in the network tab: if the key is absent there, the client never sent it; if it is present in the request but empty in 4D, the check stripped it.
Error codes
| Code | Meaning |
|---|---|
| 400 | Malformed request |
| 403 | Refused: rights, unconfigured event, failed constraint |
| 404 | Page unknown or unpublished |
| 301 / 302 | Redirect (permanent / temporary) |
On /bweb/call-action a refusal answers in JSON with the code, not with the HTML error page. A toast names the page and the function, because a silent refusal used to cost hours.
Constraints are always server-side
vb_Required, the input type and vt_PregMatch are validated here, before any hook of yours runs. A format check written in a 4D hook is therefore never reached when the value fails the schema's own constraint: the request is already refused.
Note also that a "not empty" input type makes the empty value invalid. That is the intended behaviour, but it surprises when a field is legitimately optional.
The captcha
The captcha answer is checked server-side, against the one held in the session. Still, do not rely on the captcha alone to protect a form: treat it as a speed bump against naive bots, not as a control.
See the Captcha page for how the challenge is generated and consumed.
See also
- Events and the POST: how the event reaches a function once it has passed
- The Claude API:
/_claude/*has its own, separate authorisation chain; do not expose it to the Internet

