Security

The default middleware stack ships three security layers, safe-by-default and each overridable through config. Combined with CSRF protection and the signed session cookie, a generated project is hardened without writing a line of it yourself.

Security headers

Altair::Middleware::SecurityHeaders stamps conservative headers on every response:

  • X-Content-Type-Options: nosniff
  • X-Frame-Options: SAMEORIGIN
  • Referrer-Policy: strict-origin-when-cross-origin

Each header is only written when the application did not set it itself. The set is driven by config.security_headers, so it is a plain hash you can extend or replace:

config.security_headers["X-Content-Type-Options"] = "nosniff"
config.security_headers["Content-Security-Policy"] = "default-src 'self'"

Set the hash to {} of String => String to disable the layer entirely.

Request ids

Altair::Middleware::RequestId gives every request an identifier you can carry end-to-end:

  • An inbound X-Request-Id header is honored (echoed back, not replaced).
  • Otherwise a fresh UUID is generated.
  • The value is exposed as request.request_id, echoed back on the response header, and appended to the request log line — so a log entry and the response header correlate across distributed traces.

The header name is configurable via config.request_id_header:

config.request_id_header = "X-Correlation-Id"

CORS

Altair::Middleware::Cors is a pass-through until you opt in by naming the origins you trust. Fill config.cors.origins and it stamps Access-Control-Allow-* on permitted requests and answers preflight OPTIONS directly (methods, headers, credentials, max age):

config.cors.origins = ["https://app.example.com"]
config.cors.credentials = true        # admit cookies cross-origin
config.cors.max_age = 3600            # seconds, preflight caching

Or allow any origin:

config.cors.origins = ["*"]

Notes:

  • Origins are exact-matched against the Origin header; "*" grants any.
  • With credentials = true and a "*" entry, the exact origin is echoed instead of the wildcard — browsers refuse wildcard-plus-credentials.
  • config.cors.methods and config.cors.headers tailor the preflight answer; requested headers are honored when the client names extra ones.
  • Combine CORS with the framework's signed session cookie, which carries SameSite=Lax by default, to keep cross-origin sessions honest.

The full stack

The default config.middleware runs, in order:

Layer Job
Logger Request logging with the request id appended
RequestId Assign and echo a request identifier
SecurityHeaders Stamp safe-by-default response headers
Cors Opt-in cross-origin support (pass-through by default)
Static Serve public/ files as-is

See Configuration for building your own stack.