Edit Page

Upgrade from 9.5 to 9.6

RESTHeart 9.6 changes the default behavior of originVetoer for requests with no Origin header, and fixes a gap where VETOER authorizers were not enforced on secure = false services.

This page explains the changes and how to restore previous behavior if needed.

What changed

VETOER authorizers now enforced on secure = false services

In RESTHeart 9.5, services declared with secure = false (the default for many endpoints, including all restheart-accounts authentication endpoints) skipped all authorizer checks — not just authentication. This meant originVetoer and any other VETOER authorizer never ran on those endpoints.

Starting from 9.6, VETOER authorizers are always evaluated, even on secure = false services. The FullAuthorizer (which allows all requests) is still used as the ALLOWER, so authentication remains optional, but deny rules are now enforced.

9.5 9.6

secure = false → only FullAuthorizer runs

secure = false → FullAuthorizer + all VETOERs run

originVetoer skipped on unauthenticated endpoints

originVetoer enforced on all endpoints

This affects the following restheart-accounts endpoints (all secure = false by design):

  • POST /auth/register

  • GET /auth/verify

  • POST /auth/forgot-password

  • PATCH /auth/reset-password

  • PATCH /auth/activate

  • POST /auth/invite

  • POST /auth/resend-invite

  • GET /auth/oauth/authorize/{provider}

  • GET /auth/oauth/callback/{provider}

Why this matters

A deployment that configured originVetoer in 9.5 was protected on data APIs but left registration, password reset and OAuth entry points open to any origin. This was a security gap, not a feature. The fix ensures the origin check applies consistently.

Impact on third-party plugins

If you have custom VETOER authorizers registered via @RegisterPlugin(authorizerType = Authorizer.TYPE.VETOER), they will now also run on secure = false services. Make sure your veto predicates handle requests to unrelated services gracefully (e.g. by short-circuiting on path or request type). Existing built-in vetoes (GetRoleService, AccountsInitializer) already do this.

originVetoer: allow-missing-origin default changed to true

In RESTHeart 9.5, when originVetoer was active (a whitelist or patterns were configured), a request with no Origin header was always denied. This was the correct default for browser-only APIs, but it prevented non-browser clients (curl, CLIs, backend integrations, cron jobs) from calling the API even when they were legitimate.

Starting from 9.6, the new allow-missing-origin configuration option defaults to true, meaning requests without an Origin header are allowed through. Browser requests (which always include Origin) are still validated against the whitelist as before.

9.5 9.6

Missing Origin header → denied

Missing Origin header → allowed (default)

No allow-missing-origin option

allow-missing-origin: true (default)

Why this is safe

Browsers always send the Origin header on the requests that matter for CSRF protection:

  • Cross-site POST, PUT, DELETE requests

  • Any CORS-preflighted request

Setting allow-missing-origin: true does not open a CSRF vulnerability. It simply means the vetoer no longer acts as a blanket "browser-only" gate.

Migration steps

If you want to keep the 9.5 behavior

Add allow-missing-origin: false to your originVetoer configuration in restheart.yml:

originVetoer:
  enabled: true
  whitelist:
    - https://your-frontend.example.com
  allow-missing-origin: false  # restores 9.5 behavior: missing Origin is denied

No changes required. Non-browser clients will now be able to call your API without an Origin header, while browser requests continue to be validated against the whitelist.

Per-request override (multi-tenant deployments)

For multi-tenant deployments, the allow-missing-origin setting can be overridden per request using an interceptor:

// Allow non-browser clients for this specific request
request.attachParam("override-origin-allow-missing", true);

// Or deny non-browser clients even when the static config allows them
request.attachParam("override-origin-allow-missing", false);

This is consistent with the existing override-origin-whitelist mechanism introduced in 9.5.

Configuration reference

See Security Hardening: originVetoer for the full configuration documentation.