Liking cljdoc? Tell your friends :D

wagoe.platform.shell.http.interceptors

HTTP interceptor pipeline for Ring request/response processing.

This namespace provides an HTTP-specific interceptor chain that runs over Ring handlers, giving Pedestal-like enter/leave/error semantics while maintaining Ring compatibility.

Key Benefits:

  • Consistent cross-layer observability (HTTP → service → persistence)
  • Declarative per-route policies (auth, rate-limit, auditing)
  • Clean separation of concerns (routing vs cross-cutting logic)
  • Reusable interceptor components across routes

HTTP Context Model: {:request Ring request map :response Ring response map (built up through pipeline) :route Route metadata from Reitit match :path-params Extracted path parameters :query-params Extracted query parameters :system Observability services {:logger :metrics-emitter :error-reporter} :attrs Additional attributes set by interceptors :correlation-id Unique request ID :started-at Request start timestamp}

Interceptor Shape: {:name :my-interceptor :enter (fn [context] ...) ; Process request, modify context :leave (fn [context] ...) ; Process response, modify context :error (fn [context] ...)} ; Handle exceptions, produce safe response

Usage: ;; As Ring middleware (global) (def handler (-> app-handler (wrap-http-interceptors [logging metrics error-reporting])))

;; Per-route via Reitit :middleware {:get {:handler my-handler :middleware [(interceptor-middleware [auth rate-limit])]}}

Integration with Normalized Routes:

  • Normalized routes can specify :interceptors vector
  • Reitit adapter translates :interceptors → :middleware with this runner
HTTP interceptor pipeline for Ring request/response processing.

This namespace provides an HTTP-specific interceptor chain that runs over Ring handlers,
giving Pedestal-like enter/leave/error semantics while maintaining Ring compatibility.

Key Benefits:
- Consistent cross-layer observability (HTTP → service → persistence)
- Declarative per-route policies (auth, rate-limit, auditing)
- Clean separation of concerns (routing vs cross-cutting logic)
- Reusable interceptor components across routes

HTTP Context Model:
{:request       Ring request map
 :response      Ring response map (built up through pipeline)
 :route         Route metadata from Reitit match
 :path-params   Extracted path parameters
 :query-params  Extracted query parameters
 :system        Observability services {:logger :metrics-emitter :error-reporter}
 :attrs         Additional attributes set by interceptors
 :correlation-id Unique request ID
 :started-at    Request start timestamp}

Interceptor Shape:
{:name   :my-interceptor
 :enter  (fn [context] ...) ; Process request, modify context
 :leave  (fn [context] ...) ; Process response, modify context
 :error  (fn [context] ...)} ; Handle exceptions, produce safe response

Usage:
;; As Ring middleware (global)
(def handler
  (-> app-handler
      (wrap-http-interceptors [logging metrics error-reporting])))

;; Per-route via Reitit :middleware
{:get {:handler my-handler
       :middleware [(interceptor-middleware [auth rate-limit])]}}

Integration with Normalized Routes:
- Normalized routes can specify :interceptors vector
- Reitit adapter translates :interceptors → :middleware with this runner
raw docstring

create-global-http-middlewareclj

(create-global-http-middleware system)
(create-global-http-middleware system additional-interceptors)

Creates global HTTP middleware with default observability stack.

Args: system: Map containing observability services additional-interceptors: Optional vector of additional interceptors to prepend

Returns: Ring middleware function

Creates global HTTP middleware with default observability stack.

Args:
  system: Map containing observability services
  additional-interceptors: Optional vector of additional interceptors to prepend

Returns:
  Ring middleware function
sourceraw docstring

create-http-contextclj

(create-http-context request system & [route-data])

Creates an HTTP interceptor context from a Ring request.

Args: request: Ring request map system: Map containing observability services {:logger :metrics-emitter :error-reporter} route-data: Optional Reitit route match data

Returns: HTTP context map with request details and observability services

Creates an HTTP interceptor context from a Ring request.

Args:
  request: Ring request map
  system: Map containing observability services {:logger :metrics-emitter :error-reporter}
  route-data: Optional Reitit route match data

Returns:
  HTTP context map with request details and observability services
sourceraw docstring

default-http-interceptorsclj

Default HTTP interceptor stack for observability and error handling.

Default HTTP interceptor stack for observability and error handling.
sourceraw docstring

default-security-headersclj

Default security headers for production deployment.

Provides defense-in-depth protection against common web vulnerabilities:

  • Content-Security-Policy: Prevent XSS attacks
  • X-Frame-Options: Prevent clickjacking
  • Strict-Transport-Security: Force HTTPS (with preload)
  • X-Content-Type-Options: Prevent MIME sniffing
  • Cross-Origin-Opener-Policy: Isolate top-level browsing context
  • Referrer-Policy: Control referrer information

Note: Uses Alpine.js CSP build (@alpinejs/csp) which avoids eval()/new Function(). All Alpine components are registered via Alpine.data() in components.js / admin-ux.js. 'unsafe-inline' is kept in script-src because several UI components still use inline event handlers (onclick, onchange, onsubmit) and inline [:script] blocks (e.g. Alpine store init, audit modal wiring). Remove 'unsafe-inline' only after those are externalised. 'unsafe-eval' is kept in script-src because HTMX 2.x has allowEval:true by default and hx-on::* expression attrs (e.g. hx-on::afterRequest in admin entity forms) depend on it. Remove 'unsafe-eval' only after htmx.config.allowEval is disabled or all hx-on attrs are replaced.

Default security headers for production deployment.

Provides defense-in-depth protection against common web vulnerabilities:
- Content-Security-Policy: Prevent XSS attacks
- X-Frame-Options: Prevent clickjacking
- Strict-Transport-Security: Force HTTPS (with preload)
- X-Content-Type-Options: Prevent MIME sniffing
- Cross-Origin-Opener-Policy: Isolate top-level browsing context
- Referrer-Policy: Control referrer information

Note: Uses Alpine.js CSP build (@alpinejs/csp) which avoids eval()/new Function().
All Alpine components are registered via Alpine.data() in components.js / admin-ux.js.
'unsafe-inline' is kept in script-src because several UI components still use inline
event handlers (onclick, onchange, onsubmit) and inline [:script] blocks (e.g. Alpine
store init, audit modal wiring). Remove 'unsafe-inline' only after those are externalised.
'unsafe-eval' is kept in script-src because HTMX 2.x has allowEval:true by default and
hx-on::* expression attrs (e.g. hx-on::afterRequest in admin entity forms) depend on it.
Remove 'unsafe-eval' only after htmx.config.allowEval is disabled or all hx-on attrs
are replaced.
sourceraw docstring

extract-responseclj

(extract-response context)

Extracts the Ring response from an HTTP context.

If :response exists in context, returns it. If :response is nil, returns a safe 500 error response.

Args: context: HTTP interceptor context

Returns: Ring response map

Extracts the Ring response from an HTTP context.

If :response exists in context, returns it.
If :response is nil, returns a safe 500 error response.

Args:
  context: HTTP interceptor context

Returns:
  Ring response map
sourceraw docstring

get-client-idclj

(get-client-id request)

Extracts client identifier from request for rate limiting.

Priority order:

  1. Authenticated user ID (from :user in request)
  2. API key (from headers)
  3. Remote IP address

Args: request: Ring request map

Returns: String client identifier

Extracts client identifier from request for rate limiting.

Priority order:
1. Authenticated user ID (from :user in request)
2. API key (from headers)
3. Remote IP address

Args:
  request: Ring request map

Returns:
  String client identifier
sourceraw docstring

http-correlation-headerclj

Adds correlation ID to response headers.

Adds correlation ID to response headers.
sourceraw docstring

http-csrf-protectionclj

Validates CSRF tokens for state-changing requests (POST, PUT, DELETE, PATCH) and issues tokens for rendering.

Binding model — a token is signed against, and validated with, a per-client binding so a forged cross-site request cannot produce a matching token:

  • Authenticated requests bind to the session (session-token cookie / header).
  • Unauthenticated /web flows (login, register, MFA) bind to a pre-session cookie (csrf-session, SameSite=Strict) minted on the page GET.

A state-changing request is validated (403 on failure) when CSRF is enabled, the path is not in :exempt-paths, and it is either session-authenticated or a /web route. This protects /web/admin and any session-authenticated /api route; it does NOT check token-auth API clients that send no session cookie (not CSRF-vulnerable) or exempt paths (webhooks/callbacks). Safe methods (GET/HEAD/OPTIONS) are never validated.

For rendering, the interceptor exposes a token on the request as :anti-forgery-token and binds csrf/token around handler execution, so the page

<meta> tag (HTMX) and form hidden fields emit it without per-handler threading. When the request already carries a token valid for the current binding, that token is re-issued instead of minting a new one (tokens have no expiry, so this is equivalent); a fresh token is minted only when absent or invalid.

Config is read from (:csrf system), injected by the HTTP handler wiring: {:enabled? bool, :secret <signing-key>, :exempt-paths ["/api/v1/..."]} Enforcement is opt-in: when :enabled? is absent or false the interceptor is a no-op (no validation, no issuance). Apps enable it after emitting tokens.

Validates CSRF tokens for state-changing requests (POST, PUT, DELETE, PATCH) and
issues tokens for rendering.

Binding model — a token is signed against, and validated with, a per-client
binding so a forged cross-site request cannot produce a matching token:
- Authenticated requests bind to the session (session-token cookie / header).
- Unauthenticated /web flows (login, register, MFA) bind to a pre-session cookie
  (csrf-session, SameSite=Strict) minted on the page GET.

A state-changing request is validated (403 on failure) when CSRF is enabled, the
path is not in :exempt-paths, and it is either session-authenticated or a /web
route. This protects /web/admin and any session-authenticated /api route; it does
NOT check token-auth API clients that send no session cookie (not CSRF-vulnerable)
or exempt paths (webhooks/callbacks). Safe methods (GET/HEAD/OPTIONS) are never
validated.

For rendering, the interceptor exposes a token on the request as
:anti-forgery-token and binds csrf/*token* around handler execution, so the page
<meta> tag (HTMX) and form hidden fields emit it without per-handler threading.
When the request already carries a token valid for the current binding, that
token is re-issued instead of minting a new one (tokens have no expiry, so this
is equivalent); a fresh token is minted only when absent or invalid.

Config is read from (:csrf system), injected by the HTTP handler wiring:
  {:enabled? bool, :secret <signing-key>, :exempt-paths ["/api/v1/..."]}
Enforcement is opt-in: when :enabled? is absent or false the interceptor is a
no-op (no validation, no issuance). Apps enable it after emitting tokens.
sourceraw docstring

http-error-handlerclj

Converts exceptions into safe HTTP error responses.

Converts exceptions into safe HTTP error responses.
sourceraw docstring

http-error-reportingclj

Captures HTTP exceptions and reports them to error tracking.

Captures HTTP exceptions and reports them to error tracking.
sourceraw docstring

http-metrics-bucketsclj

Default latency histogram buckets in SECONDS (Prometheus/OTel convention).

Default latency histogram buckets in SECONDS (Prometheus/OTel convention).
sourceraw docstring

http-rate-limitclj

(http-rate-limit)
(http-rate-limit limit window-ms)
(http-rate-limit limit window-ms cache)

Creates a rate limiting interceptor with fixed limit/window/cache.

With a cache argument, uses Redis fixed-window counting — safe for multi-instance deployments and survives process restarts. Without a cache argument, falls back to an in-process sliding window.

For the framework default pipeline use the config-driven http-rate-limit-protection instead; this fixed-arg form is for explicit per-route limits and standalone wiring (e.g. the devtools dashboard).

Args: limit: Maximum requests per time window (default: 100) window-ms: Time window in milliseconds (default: 60000 = 1 minute) cache: (optional) IAtomicCache + ICache implementation for distributed limiting

Returns: Rate limiting interceptor map

Example: (http-rate-limit) ; 100 req/min, in-memory (http-rate-limit 30 60000) ; 30 req/min, in-memory (http-rate-limit 100 60000 cache) ; 100 req/min, Redis-backed

Creates a rate limiting interceptor with fixed limit/window/cache.

With a cache argument, uses Redis fixed-window counting — safe for
multi-instance deployments and survives process restarts.
Without a cache argument, falls back to an in-process sliding window.

For the framework default pipeline use the config-driven
`http-rate-limit-protection` instead; this fixed-arg form is for explicit
per-route limits and standalone wiring (e.g. the devtools dashboard).

Args:
  limit:        Maximum requests per time window (default: 100)
  window-ms:    Time window in milliseconds (default: 60000 = 1 minute)
  cache:        (optional) IAtomicCache + ICache implementation for distributed limiting

Returns:
  Rate limiting interceptor map

Example:
  (http-rate-limit)                   ; 100 req/min, in-memory
  (http-rate-limit 30 60000)          ; 30 req/min, in-memory
  (http-rate-limit 100 60000 cache)   ; 100 req/min, Redis-backed
sourceraw docstring

http-rate-limit-protectionclj

Config-driven rate limiter applied in the default HTTP interceptor stack.

Reads its policy from the system map injected by the HTTP handler wiring: (:rate-limit system) => {:enabled? bool, :limit int, :window-ms int} (:cache system) => IAtomicCache (Redis) for cross-replica limiting

Enforcement is opt-in: when :enabled? is absent or false the interceptor is a no-op, so a framework upgrade cannot start 429-ing consumers that have not configured limits. When enabled it uses the Redis cache for a limit shared across all replicas; with no cache it falls back to a per-process counter — correct on a single node only, NOT a global limit across replicas.

Config-driven rate limiter applied in the default HTTP interceptor stack.

Reads its policy from the system map injected by the HTTP handler wiring:
  (:rate-limit system) => {:enabled? bool, :limit int, :window-ms int}
  (:cache system)      => IAtomicCache (Redis) for cross-replica limiting

Enforcement is opt-in: when :enabled? is absent or false the interceptor is a
no-op, so a framework upgrade cannot start 429-ing consumers that have not
configured limits. When enabled it uses the Redis cache for a limit shared
across all replicas; with no cache it falls back to a per-process counter —
correct on a single node only, NOT a global limit across replicas.
sourceraw docstring

http-request-loggingclj

Logs HTTP requests at entry and completion.

Logs HTTP requests at entry and completion.
sourceraw docstring

http-request-metricsclj

Records HTTP request count, error count, and latency (seconds) on the metrics emitter. http.requests is incremented for every response (success and error, with a status label); http.requests.errors additionally counts the error path. Handles are registered once at wiring and threaded in as :metrics-handles on the system map; a no-op when no metrics component is configured, so this is safe always-on.

Records HTTP request count, error count, and latency (seconds) on the metrics
emitter. `http.requests` is incremented for every response (success *and*
error, with a `status` label); `http.requests.errors` additionally counts the
error path. Handles are registered once at wiring and threaded in as
`:metrics-handles` on the system map; a no-op when no metrics component is
configured, so this is safe always-on.
sourceraw docstring

http-request-tracingclj

Starts a distributed-tracing span per HTTP request and ends it on completion, recording the response status (and any exception). No-op unless a tracer is wired into :system (:no-op tracer by default), so this is safe always-on.

The span is a per-request root: cross-thread propagation into service / persistence spans is a later enhancement (would need context support on the ITracer port).

Starts a distributed-tracing span per HTTP request and ends it on completion,
recording the response status (and any exception). No-op unless a tracer is
wired into `:system` (:no-op tracer by default), so this is safe always-on.

The span is a per-request root: cross-thread propagation into service /
persistence spans is a later enhancement (would need context support on the
`ITracer` port).
sourceraw docstring

http-security-headersclj

(http-security-headers)
(http-security-headers headers)

Creates security headers interceptor with configurable headers.

Args: headers - Optional map of security headers (defaults to default-security-headers)

Returns: Interceptor that adds security headers to responses

Examples: ;; Use default security headers (http-security-headers)

;; Custom CSP for development (allows unsafe-eval for hot reload) (http-security-headers {"Content-Security-Policy" "default-src 'self' 'unsafe-eval'; ..." "X-Frame-Options" "SAMEORIGIN"})

;; Disable HSTS in development (http-security-headers (dissoc default-security-headers "Strict-Transport-Security"))

Security Headers Explained:

  • Content-Security-Policy (CSP): Defines approved sources for loading content (scripts, styles, images, etc.) Prevents XSS attacks by restricting where resources can be loaded from Current policy:

    • default-src 'self' - Only load resources from same origin by default
    • script-src - Allow scripts from self + HTMX from CDN
    • style-src - Allow styles from self + Pico CSS from CDN
    • img-src - Allow images from self, data URLs, and HTTPS
    • frame-ancestors 'none' - Prevent embedding in iframes (clickjacking)
  • X-Frame-Options: DENY Legacy header (superseded by CSP frame-ancestors) Prevents page from being embedded in iframe/frame Protects against clickjacking attacks

  • Strict-Transport-Security (HSTS): Forces browsers to use HTTPS for 1 year Prevents protocol downgrade attacks includeSubDomains applies to all subdomains

  • X-Content-Type-Options: nosniff Prevents browser from MIME-sniffing responses Forces browser to respect Content-Type header

  • X-XSS-Protection: 1; mode=block Legacy XSS filter (modern browsers use CSP instead) Tells browser to block page if XSS attack detected

  • Referrer-Policy: strict-origin-when-cross-origin Controls Referer header sent with requests Only sends origin (not full URL) on cross-origin requests

  • Permissions-Policy: Controls browser features (geolocation, camera, microphone) Denies access to sensitive features by default

Environment-Specific Recommendations:

Development:

  • Relax CSP to allow hot reload: 'unsafe-eval', 'unsafe-inline'
  • Use X-Frame-Options: SAMEORIGIN (for development tools)
  • Omit HSTS (HTTP development servers)

Staging:

  • Stricter CSP (fewer 'unsafe-*' directives)
  • Include HSTS with shorter max-age (e.g., 86400 = 1 day)

Production:

  • Strictest CSP (no 'unsafe-*' if possible)
  • HSTS with max-age=31536000 (1 year)
  • Consider adding preload directive for HSTS
Creates security headers interceptor with configurable headers.

Args:
  headers - Optional map of security headers (defaults to default-security-headers)

Returns:
  Interceptor that adds security headers to responses

Examples:
  ;; Use default security headers
  (http-security-headers)

  ;; Custom CSP for development (allows unsafe-eval for hot reload)
  (http-security-headers
    {"Content-Security-Policy" "default-src 'self' 'unsafe-eval'; ..."
     "X-Frame-Options" "SAMEORIGIN"})

  ;; Disable HSTS in development
  (http-security-headers
    (dissoc default-security-headers "Strict-Transport-Security"))

Security Headers Explained:

- Content-Security-Policy (CSP):
  Defines approved sources for loading content (scripts, styles, images, etc.)
  Prevents XSS attacks by restricting where resources can be loaded from
  Current policy:
    * default-src 'self' - Only load resources from same origin by default
    * script-src - Allow scripts from self + HTMX from CDN
    * style-src - Allow styles from self + Pico CSS from CDN
    * img-src - Allow images from self, data URLs, and HTTPS
    * frame-ancestors 'none' - Prevent embedding in iframes (clickjacking)

- X-Frame-Options: DENY
  Legacy header (superseded by CSP frame-ancestors)
  Prevents page from being embedded in iframe/frame
  Protects against clickjacking attacks

- Strict-Transport-Security (HSTS):
  Forces browsers to use HTTPS for 1 year
  Prevents protocol downgrade attacks
  includeSubDomains applies to all subdomains

- X-Content-Type-Options: nosniff
  Prevents browser from MIME-sniffing responses
  Forces browser to respect Content-Type header

- X-XSS-Protection: 1; mode=block
  Legacy XSS filter (modern browsers use CSP instead)
  Tells browser to block page if XSS attack detected

- Referrer-Policy: strict-origin-when-cross-origin
  Controls Referer header sent with requests
  Only sends origin (not full URL) on cross-origin requests

- Permissions-Policy:
  Controls browser features (geolocation, camera, microphone)
  Denies access to sensitive features by default

Environment-Specific Recommendations:

Development:
  - Relax CSP to allow hot reload: 'unsafe-eval', 'unsafe-inline'
  - Use X-Frame-Options: SAMEORIGIN (for development tools)
  - Omit HSTS (HTTP development servers)

Staging:
  - Stricter CSP (fewer 'unsafe-*' directives)
  - Include HSTS with shorter max-age (e.g., 86400 = 1 day)

Production:
  - Strictest CSP (no 'unsafe-*' if possible)
  - HSTS with max-age=31536000 (1 year)
  - Consider adding preload directive for HSTS
sourceraw docstring

interceptor-middlewareclj

(interceptor-middleware interceptors system)

Creates a Ring middleware function from interceptors.

This is useful for Reitit per-route :middleware.

Usage: {:get {:handler my-handler :middleware [(interceptor-middleware [auth rate-limit] system)]}}

Args: interceptors: Vector of interceptor maps system: Map containing observability services

Returns: Ring middleware function (handler → wrapped-handler)

Creates a Ring middleware function from interceptors.

This is useful for Reitit per-route :middleware.

Usage:
  {:get {:handler my-handler
         :middleware [(interceptor-middleware [auth rate-limit] system)]}}

Args:
  interceptors: Vector of interceptor maps
  system: Map containing observability services

Returns:
  Ring middleware function (handler → wrapped-handler)
sourceraw docstring

merge-response-headersclj

(merge-response-headers context headers)

Merges additional headers into the response.

Args: context: HTTP interceptor context headers: Map of headers to merge

Returns: Updated context with merged headers

Merges additional headers into the response.

Args:
  context: HTTP interceptor context
  headers: Map of headers to merge

Returns:
  Updated context with merged headers
sourceraw docstring

register-http-metrics!clj

(register-http-metrics! metrics)

Register the standard HTTP request metrics on a metrics component once (at wiring time). Returns a handles map {:requests :errors :duration}, or nil when there is no metrics component. Registering once — rather than per request — is required: some adapters (e.g. datadog) reset a counter on re-register.

Register the standard HTTP request metrics on a metrics component once (at
wiring time). Returns a handles map `{:requests :errors :duration}`, or nil
when there is no metrics component. Registering once — rather than per request
— is required: some adapters (e.g. datadog) reset a counter on re-register.
sourceraw docstring

run-http-interceptorsclj

(run-http-interceptors handler interceptors request system)

Runs an HTTP interceptor pipeline around a Ring handler.

Args: handler: Ring handler function (request → response) interceptors: Vector of interceptor maps request: Ring request map system: Map containing observability services

Returns: Ring response map

Pipeline execution:

  1. Create HTTP context from request
  2. Run :enter phase on all interceptors
  3. If successful, call handler and set :response in context
  4. Run :leave phase on all interceptors (reverse order)
  5. If exception occurs, run :error phase to produce safe response
  6. Extract and return final Ring response
Runs an HTTP interceptor pipeline around a Ring handler.

Args:
  handler: Ring handler function (request → response)
  interceptors: Vector of interceptor maps
  request: Ring request map
  system: Map containing observability services

Returns:
  Ring response map

Pipeline execution:
1. Create HTTP context from request
2. Run :enter phase on all interceptors
3. If successful, call handler and set :response in context
4. Run :leave phase on all interceptors (reverse order)
5. If exception occurs, run :error phase to produce safe response
6. Extract and return final Ring response
sourceraw docstring

set-responseclj

(set-response context response)

Sets the Ring response in the HTTP context.

Args: context: HTTP interceptor context response: Ring response map

Returns: Updated context with response

Sets the Ring response in the HTTP context.

Args:
  context: HTTP interceptor context
  response: Ring response map

Returns:
  Updated context with response
sourceraw docstring

update-response-bodyclj

(update-response-body context f)

Updates the response body using a function.

Args: context: HTTP interceptor context f: Function to apply to existing body

Returns: Updated context with modified body

Updates the response body using a function.

Args:
  context: HTTP interceptor context
  f: Function to apply to existing body

Returns:
  Updated context with modified body
sourceraw docstring

validate-http-interceptorclj

(validate-http-interceptor interceptor)

Validates that an interceptor is suitable for HTTP use.

HTTP interceptors should handle HTTP context properly and produce valid Ring responses.

Validates that an interceptor is suitable for HTTP use.

HTTP interceptors should handle HTTP context properly and produce valid Ring responses.
sourceraw docstring

wrap-csrfclj

(wrap-csrf handler {:keys [enabled? secret exempt-paths] :or {enabled? false}})

Ring-middleware form of http-csrf-protection, for handlers that run OUTSIDE the interceptor stack — e.g. an app that mounts its own routes in front of the platform handler and so never passes through the default interceptor chain.

Identical binding model and semantics to the interceptor:

  • State-changing (POST/PUT/DELETE/PATCH) requests that are not exempt and are either session-authenticated or a /web route are validated against the session token / pre-session cookie binding; a bad or absent token yields 403 and the wrapped handler does not run.
  • Safe or authenticated requests issue a token and bind csrf/*token* around the handler, so form hidden-fields and the page <meta> tag emit it without per-handler threading.
  • An unauthenticated /web page load mints a pre-session binding and sets the csrf-session cookie on the response (for login/register/MFA forms).
  • Safe methods (GET/HEAD/OPTIONS) and token-auth API clients (no session cookie, not CSRF-vulnerable) are never blocked.

Opt-in: a falsy/absent :enabled? or a blank :secret makes it a pass-through.

Config: {:enabled? bool :secret <signing-key> :exempt-paths ["/..."]}.

Ring-middleware form of `http-csrf-protection`, for handlers that run OUTSIDE
the interceptor stack — e.g. an app that mounts its own routes in front of the
platform handler and so never passes through the default interceptor chain.

Identical binding model and semantics to the interceptor:
- State-changing (POST/PUT/DELETE/PATCH) requests that are not exempt and are
  either session-authenticated or a /web route are validated against the
  session token / pre-session cookie binding; a bad or absent token yields 403
  and the wrapped handler does not run.
- Safe or authenticated requests issue a token and bind `csrf/*token*` around
  the handler, so form hidden-fields and the page `<meta>` tag emit it without
  per-handler threading.
- An unauthenticated /web page load mints a pre-session binding and sets the
  `csrf-session` cookie on the response (for login/register/MFA forms).
- Safe methods (GET/HEAD/OPTIONS) and token-auth API clients (no session
  cookie, not CSRF-vulnerable) are never blocked.

Opt-in: a falsy/absent `:enabled?` or a blank `:secret` makes it a pass-through.

Config: {:enabled? bool :secret <signing-key> :exempt-paths ["/..."]}.
sourceraw docstring

wrap-http-interceptorsclj

(wrap-http-interceptors handler interceptors system)

Ring middleware that runs HTTP interceptors around a handler.

Usage: (def handler (-> my-handler (wrap-http-interceptors [auth logging metrics] system)))

Args: handler: Ring handler function interceptors: Vector of interceptor maps system: Map containing observability services

Returns: Wrapped Ring handler function

Ring middleware that runs HTTP interceptors around a handler.

Usage:
  (def handler
    (-> my-handler
        (wrap-http-interceptors [auth logging metrics] system)))

Args:
  handler: Ring handler function
  interceptors: Vector of interceptor maps
  system: Map containing observability services

Returns:
  Wrapped Ring handler function
sourceraw docstring

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
Move to previous article
Move to next article
Ctrl+/Jump to the search field
× close