Registered by the plugin at priority 260: after security headers (250) so a
rejected request never loads a session, and before authentication (300) so an
auth strategy can read one.
The commit runs after next() returns. That works even though the handler has
already called a terminal response method, because the kernel's response
builder appends headers without consulting whether it ended, and hands the
adapter its live Headers rather than a clone — cloning would collapse
repeated Set-Cookie values into one comma-joined header.
A request that throws is deliberately not committed: the error handler is
about to replace the response, and persisting a half-applied mutation from a
failed request is worse than dropping it.
Tenant binding (default on): when a tenant is resolved for the request, the
session is sealed with that tenant id before it commits, and a later request
that presents a session bound to a different tenant is refused with 403
before the handler runs. When either the session or the request carries no
tenant, nothing is compared, so an application without tenancy is inert.
The compare runs on whichever side sees the tenant second (M101c, V8-7):
this middleware compares at load time, which covers every tenant resolved
before it (the shipped resolvers at the default priority 40); the
multi-tenancy middleware runs the SAME compare (tenantBindingMismatch in
common) right after it stamps a tenant, which covers a tenant resolved
after this middleware. Middleware priority therefore does not matter. The
seal runs only for a session that carries NO binding: a bound session is
never rebound, so a refusal (or a tenant written by application code inside
a handler) cannot re-seal the session to the tenant it was just refused
under.
Builds the session middleware.
Registered by the plugin at priority 260: after security headers (250) so a rejected request never loads a session, and before authentication (300) so an auth strategy can read one.
The commit runs after
next()returns. That works even though the handler has already called a terminal response method, because the kernel's response builder appends headers without consulting whether it ended, and hands the adapter its liveHeadersrather than a clone — cloning would collapse repeatedSet-Cookievalues into one comma-joined header.A request that throws is deliberately not committed: the error handler is about to replace the response, and persisting a half-applied mutation from a failed request is worse than dropping it.
Tenant binding (default on): when a tenant is resolved for the request, the session is sealed with that tenant id before it commits, and a later request that presents a session bound to a different tenant is refused with
403before the handler runs. When either the session or the request carries no tenant, nothing is compared, so an application without tenancy is inert.The compare runs on whichever side sees the tenant second (M101c, V8-7): this middleware compares at load time, which covers every tenant resolved before it (the shipped resolvers at the default priority 40); the multi-tenancy middleware runs the SAME compare (
tenantBindingMismatchincommon) right after it stamps a tenant, which covers a tenant resolved after this middleware. Middleware priority therefore does not matter. The seal runs only for a session that carries NO binding: a bound session is never rebound, so a refusal (or a tenant written by application code inside a handler) cannot re-seal the session to the tenant it was just refused under.