HTTP transport adapter for RpcElixir implemented as a Plug.
Mounts a router module at a configurable path prefix, decodes JSON bodies, dispatches to the procedure pipeline, drains response cookies and headers onto the conn, and renders JSON responses.
Options
:router(required) — module usingRpcElixir.Router.:path_prefix(optional, default"/rpc") — the prefix to strip from the request path before procedure dispatch. A request toPOST /rpc/users.getdispatches procedure"users.get".:ctx_builder(optional) —(Plug.Conn.t() -> RpcElixir.Context.t()). When provided, the returned context is used as the base, but the transport always overwrites its:reqfield with conn-derived metadata (cookies, headers, remote_ip, session), so those fields are always present regardless of what the builder returns.:max_body_size(optional, default 8 MB) — maximum request body size in bytes. Bodies exceeding this are rejected with 413:payload_too_large.:max_body_depth(optional, default 64) — maximum structural nesting depth of the decoded JSON body. Payloads nested deeper are rejected with 400:input_validation_failedbefore validation runs, bounding stack and CPU use that the byte cap alone cannot.:require_content_type(optional, defaulttrue) — whentrue, requests must carry acontent-typeofapplication/json(charset/params allowed); otherwise they are rejected with 415:unsupported_media_type. See## Security / CSRF.:allowed_origins(optional, defaultnil= disabled) — when set to a list of origin strings, a request carrying anoriginheader not in the list is rejected with 403:forbidden. See## Security / CSRF.
Security / CSRF
This adapter dispatches state-changing RPC over POST and can pair with
cookie-based sessions (see ## Session integration). That combination is a
CSRF surface: a cross-site page can auto-submit a form to an RPC endpoint and
the browser will attach the session cookie, so without a defense an attacker
could trigger authenticated calls.
Two mitigations are enforced here:
- Content-Type enforcement (
:require_content_type, defaulttrue). Requiringapplication/jsonmeans a request can no longer be a "simple" cross-site request — browsers must send a CORS preflight that the server never approves, and HTML forms (which can only sendapplication/x-www-form-urlencoded,multipart/form-data, ortext/plain) are blocked outright. This is the primary CSRF defense. - Origin allow-listing (
:allowed_origins, default disabled). When configured, requests whoseoriginheader is present but not allow-listed are rejected with 403. This is defense-in-depth for browsers that sendOriginon state-changing requests.
The bundled JS client always sends Content-Type: application/json, so the
default-on enforcement does not affect legitimate usage.
Session integration
To enable session support, configure Plug.Session earlier in your pipeline.
The adapter reads the session into ctx.req.session and drains
Resolution.resp_session back into the session after dispatch.
defmodule MyApp.Router do
use Plug.Builder
plug Plug.Session,
store: :cookie,
key: "_my_app_session",
signing_salt: "my_salt"
plug :fetch_session
plug RpcElixir.Plug, router: MyApp.RpcRouter
endWithin middleware, use Resolution.put_session/3, delete_session/2, or
clear_session/1 to modify the session. Read session data via
res.ctx.req[:session].
Example
plug RpcElixir.Plug, router: MyApp.RpcRouterResponse draining order
After dispatch, session mutations, cookies, and headers are all applied to
the conn before render_result writes the response body. This ordering is
required by Plug: session and cookie mutations must precede the response.