Skip to content

Build on core's API framework instead of shipping one - #249

Draft
luke- wants to merge 7 commits into
developfrom
vue
Draft

Build on core's API framework instead of shipping one#249
luke- wants to merge 7 commits into
developfrom
vue

Conversation

@luke-

@luke- luke- commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Draft — companion to humhub/humhub#8403, which moves the HTTP API framework into core.
Depends on that branch (HumHub 1.19 + the core humhub\components\api namespace).

What changes

Core now ships the API framework and its own endpoints under /api/v2. This module keeps what
is genuinely integration territory and stops duplicating the rest.

  • components/auth/AuthMethods bundles the token methods (JWT, Bearer, query param, Basic,
    Impersonate) in one place. They are used by this module's own controllers and contributed
    to every core API controller through BaseController::EVENT_COLLECT_AUTH_METHODS. So an
    installation with this module can call the core endpoints with a token; a core-only
    installation has browser-session authentication and nothing else.
  • The module's own session authentication is gone — the SessionAuth class, the
    enableSessionAuth setting and its admin field. Browser-session access is a core opt-in per
    endpoint, which returns /api/v1 to token-only. That is less attack surface than before:
    session authentication deliberately bypasses the user allowlist, while the endpoints here
    (and in the 13 modules extending components/BaseController) are written for token clients.
  • URL-space hardening: the admin-page rule and the /rest/... catch-all are registered for
    every request, and a REST controller reached off the api/v1/ prefix fails with a 404 before
    authentication runs.
  • Fix: impersonate-token authentication crashed on HumHub 1.19, which removed
    user->isImpersonated (Hide private content while impersonating a user humhub#8372).

Documentation

  • docs/api-stack.md — this module's role in the platform API stack: what it provides, the
    authentication model, the URL guards, version bounds.
  • docs/swagger/v2/ — core's /api/v2 endpoints (comment, like, account), documented here
    until core ships its own sources, deliberately in their own directory so that move is a
    rename rather than a rewrite. Every published /api/v1 documentation URL keeps its meaning.
    build-all.sh renders subdirectories and no longer builds a page for the shared-components
    file.

Compatibility

The 13 module repositories extending components/BaseController need no change — they depend
on this module providing that class, not on any core API, and their endpoints keep behaving
exactly as before.

The previous module line still needs a humhub.maxVersion, so the marketplace stops offering a
version without the core API stack for 1.19+ (the released 0.12.x additionally crashes on
impersonate-token auth there).

Verification

api suite green (77 tests, 506 assertions). Verified live against a 1.19 instance: a token
request reaches the core /api/v2 endpoints, a browser session does not authenticate
/api/v1, and off-prefix REST controller URLs 404.

luke- and others added 7 commits August 21, 2026 11:47
Accept the regular HumHub browser session as an API auth method
(SessionAuth, last in the CompositeAuth chain — token methods take
precedence). State-changing session-authenticated requests require the
CSRF token (X-CSRF-Token) and fail with a 403 JSON response otherwise;
token-authenticated requests stay CSRF-exempt.

Session auth deliberately bypasses the API user allowlist: a session
grants nothing beyond what the same user can already do in the web UI,
and the browser frontend must work for every logged-in user.

Controlled by the new enableSessionAuth setting, enabled by default on
this branch for the Vue islands experiment.
Core 1.19 replaced the Impersonator user-component behavior with the
session-bound Impersonation component (core #8372); the public
isImpersonated flag ImpersonateAuth used to set no longer exists and
setting it threw an UnknownPropertyException on every impersonate-token
request. The API user component is session-less, so there is no
session-bound impersonation state to mark instead; applying 1.19's
private-content restriction to impersonate-token requests is a separate
follow-up.
Serve the payloads the core comment/like Vue islands consume 1:1 under
/api/v1 by delegating to the core JSON services (CommentJsonService,
UserJsonService, LikeService) instead of re-modelling them in
Definitions:

- GET  comment/window            -> serializeWindow (cursor/anchor window)
- GET  comment/<id>/full         -> serializeComment (showBlocked reveal)
- POST comment/full              -> create, 422 {errors} contract
- PUT  comment/<id>/full         -> update, 422 {errors} contract
- GET  comment/<id>/full/edit    -> raw markdown for the editor
- DEL  comment/<id>/full         -> delete incl. admin notify flow
- GET  like/info, POST/DELETE like, GET like/user-list (recordId-keyed,
  user-list limit clamped to userListPaginationSize)

All new routes are flagged unstable/UI-coupled; the existing REST
endpoints and their envelope stay untouched. Viewer-context fields,
blocked-author masking, the guestHideComments gate and the extensions
namespace come from the delegated services.

Guest access mirrors the core controllers via the new
BaseController::$guestAllowedActions list (authenticator 'optional'
wiring), honored only while guest access is enabled globally.

See docs/vue-session-api.md for the full route table and contract
notes.
…personation

- Register the bare /rest/ catch-all for every request and hard-fail non-API
  paths in BaseController so no action runs off-rule as an unconstrained,
  CSRF-exempt request; add per-action verb guards on the mutating endpoints
- Enforce the browser gates (2FA and other non-API gates) for session-
  authenticated requests, which core would otherwise skip by misclassifying
  the session-less API request as an API request
- Reject session-bound admin impersonation on the API (fail closed) since the
  1.19 private-content restriction cannot apply to the session-less user
- Validate the CSRF token without ever minting a _csrf Set-Cookie
- Default enableSessionAuth to disabled like every other auth method
HumHub 1.19 ships the HTTP API framework in core (`humhub\components\api`),
with its own endpoints under `/api/v2`. This module keeps what is genuinely
integration territory - the token authentication methods, the user allowlist,
the admin UI and `/api/v1` - and stops duplicating the rest:

- `components/auth/AuthMethods` bundles the token methods (JWT, Bearer, query
  param, Basic, Impersonate) in one place, used by this module's own controllers
  and contributed to every core API controller through
  `BaseController::EVENT_COLLECT_AUTH_METHODS`. An installation with this module
  can therefore call the core endpoints with a token; a core-only installation
  has browser-session authentication and nothing else.
- The module's own session authentication is gone (`SessionAuth`, the
  `enableSessionAuth` setting and its admin field). Browser-session access is a
  core opt-in per endpoint, so `/api/v1` is token-only again - less attack
  surface than before, since session auth deliberately bypasses the user
  allowlist and the endpoints here are written for token clients.
- The `/rest/...` URL space is sealed off for every request (admin page rule
  plus catch-all), and a REST controller reached off the `api/v1/` prefix fails
  with a 404 before authentication runs.

Documentation: `docs/api-stack.md` describes this module's role in the platform
API stack, and `docs/swagger/v2/` documents core's `/api/v2` endpoints until
core ships its own sources - in its own directory so that move is a rename, not
a rewrite. `build-all.sh` renders it to `docs/html/v2/` and no longer builds a
page for the shared-components file.

Requires HumHub 1.19.
The `/api/v2` reference is part of HumHub core now (`docs/api/`, served by
every installation), so this module's Swagger sources cover its own
`/api/v1` surface again and the v2 copies here are removed.

The API framework this module builds on ships in core 1.20, which is what
`humhub.minVersion` now says — the 0.12.x line stays for 1.19 and gets an
upper bound of its own.
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.

1 participant