Skip to content
scalive
Menu
ConnectingLiveReconnectingOffline
GitHub

Configuration

Before You Start

You need to know whether browsers will use HTTP or HTTPS and which socket and asset paths the application will expose. The quick start provides a complete baseline if you do not yet have an assembled application.

Current Configuration Contract

Scalive does not read environment variables or own process-wide endpoint configuration. The application loads and validates its settings, then constructs one ZioHttpConfig for the LiveView transport:

scala
import java.time.Duration

val transportConfig = ZioHttpConfig(
  signingSecret = requiredSecret,
  sessionMaxAge = Duration.ofDays(7),
  secureCookie = true,
  allowedWebSocketOrigins = Set(WebSocketOrigin.https("example.com"))
).fold(error => throw IllegalArgumentException(error.toString), identity)

val liveRoutes = ZioHttp.routes(application, transportConfig)

All four values are required:

SettingMeaning and validationProduction guidance
signingSecretSigns framework-issued LiveView and CSRF values. Construction rejects secrets shorter than 32 UTF-8 bytes. Values are authenticated, not encrypted.Load a stable, high-entropy secret through the application's secret facility. Every replica must use the same value. Changing it invalidates outstanding signed values.
sessionMaxAgeMaximum accepted age for framework-issued LiveView and CSRF values. Construction rejects zero or negative durations. HTTP flash values have an independent 60-second lifetime.Choose an explicit policy. This setting does not define authentication-session retention or make a browser cookie persistent.
secureCookieControls the Secure attribute on framework cookies and cookies created through LiveSecurity.cookies. Scalive does not infer it from TLS or proxy headers.Use true whenever the browser-facing origin is HTTPS. Local plain HTTP normally requires false.
allowedWebSocketOriginsNon-empty set of exact canonical browser origins admitted for WebSocket upgrades. Construction rejects a set with no usable origin. WebSocketOrigin normalizes scheme and host case, default ports, and IP literals.List every browser-facing page origin that may connect. Browser origins use http or https, not the socket URL's ws or wss scheme. Add explicit non-default ports, such as WebSocketOrigin.https("example.com", 8443).

Use the throwing WebSocketOrigin.http and WebSocketOrigin.https constructors for trusted source literals. Parse deployment input through WebSocketOrigin.parse so an invalid value remains in the startup error channel. For example, load a comma-separated set without logging the untrusted value:

scala
def parseOrigins(value: String): Either[String, Set[WebSocketOrigin]] =
  val entries = value.split(",", -1).iterator.map(_.trim).toVector
  if entries.isEmpty || entries.exists(_.isEmpty) then
    Left("SCALIVE_ALLOWED_ORIGINS must contain only non-empty origins")
  else
    entries.zipWithIndex.foldLeft[Either[String, Set[WebSocketOrigin]]](Right(Set.empty)) {
      case (validated, (entry, index)) =>
        for
          origins <- validated
          origin <- WebSocketOrigin.parse(entry).left.map(error =>
                      s"SCALIVE_ALLOWED_ORIGINS entry ${index + 1}: ${error.message}"
                    )
        yield origins + origin
    }

val transportConfig =
  (for
    rawOrigins <- sys.env
                    .get("SCALIVE_ALLOWED_ORIGINS")
                    .toRight("SCALIVE_ALLOWED_ORIGINS is required")
    origins <- parseOrigins(rawOrigins)
    config <- ZioHttpConfig(
                signingSecret = requiredSecret,
                sessionMaxAge = Duration.ofDays(7),
                secureCookie = true,
                allowedWebSocketOrigins = origins
              ).left.map(_.toString)
  yield config).fold(error => throw IllegalArgumentException(error), identity)

When configuration supplies a trusted scheme separately from a dynamic host or port, use httpEither or httpsEither instead.

The policy is a finite exact set. Wildcard hosts, suffix matching, request-derived origins, and custom predicates are intentionally unsupported. Unicode host input is rejected; configure the ASCII/punycode host serialized by the browser. Origins compare by canonical scheme, host, and effective port, so scheme and host case and an omitted default port do not create separate origins. Programmatic http and https constructors also canonicalize equivalent IP literal spellings; WebSocketOrigin.parse requires a browser-serialized origin.

Construct the value once and reuse it. ZioHttp.routes also validates the assembled Live route catalog, rejecting duplicate live-session names and duplicate rendered paths before the server starts.

Share Security With HTTP Handlers

Construct LiveSecurity when ordinary HTTP handlers need the same CSRF, flash, or cookie policy as Live routes:

scala
val security = LiveSecurity(transportConfig)
val liveRoutes = ZioHttp.routes(application, security)

Cookies produced by these helpers are host-only, root-scoped, HttpOnly, and SameSite=Lax. Their Secure attribute comes from secureCookie. The current API does not configure another cookie domain, path, same-site value, or HttpOnly policy.

Use the same LiveSecurity value in checked form handlers and HTTP-to-Live flash redirects. Do not place passwords, access tokens, cookie values, or other secrets inside signed session claims or flash values: a browser can read signed content.

Configure Routes And Assets

The remaining framework choices are made while assembling the application:

ConcernAPI and defaultRequirement
Live socketLive.router.withSocketPath; default /liveConfigure the Phoenix client with the same mount. The WebSocket upgrade is the mount's /websocket child, /live/websocket by default.
Root and Live layoutsLive.router.withRootLayout and .withLayout; identity root and no ordinary layouts by defaultSupply a complete <html>, <head>, and <body> root with the application assets. Scalive inserts its CSRF metadata into the <head>.
Packaged Phoenix clientsLiveViewClientAssets.load; default mount /_scalive/live-viewUnless a custom bundle imports both npm clients, load once at startup, add clientAssets.routes, and render phoenixScript before liveViewScript and the application bootstrap. Pass another mount to load when the default conflicts with application routing.
Static assetsStaticAssetConfig.classpath, .directory, .deploymentClasspath, or .deploymentDirectory; default mount /staticLoad assets before startup, add assets.routes, and render versioned or final URLs from the same loaded value.

Use classpath or directory when Scalive should version one complete relative output tree. Use deploymentClasspath or deploymentDirectory when an external build owns exact final filenames and cache policy through a deployment manifest.

The Scala and JavaScript socket paths must agree:

scala
val application = Live.router
  .withSocketPath(PathCodec.empty / "socket")(
    Routes.home -> HomeLiveView()
  )
js
const liveSocket = new LiveView.LiveSocket("/socket", Phoenix.Socket, { params })

Use Client setup and static assets for asset sources, versioned paths, deployment manifests, cache policy, and complete browser wiring.

Observe Lifecycle Operations

Pass one LifecycleObserver as the third route argument. The built-in adapter records fixed, low-cardinality ZIO metrics for disconnected renders, joins, mounts, connected turns, failures, queue pressure, and lifecycle termination:

scala
val liveRoutes = ZioHttp.routes(
  application,
  security,
  LifecycleMetrics.observer
)

Use Lifecycle observability for safe custom observers, the complete metric and label contract, exporter verification, cardinality rules, and the boundary between lifecycle and endpoint instrumentation.

Configure The Server Separately

The application and ZIO HTTP own environment-variable names, bind address, port, direct TLS, server request handling, idle timeouts, response compression, and graceful-shutdown timeout. Configure those through ZIO HTTP's Server.Config or the application's preferred configuration library; they are not fields of ZioHttpConfig.

Public URL generation and trusted-proxy policy remain application concerns. Validate a public URL when the application needs to generate absolute URLs. WebSocket origin admission is instead transport configuration: every upgrade must contain exactly one valid Origin matching allowedWebSocketOrigins. Missing, null, malformed, duplicate, combined, or mismatched values receive HTTP 403 before upgrade. Scalive never derives origin trust from Host, Forwarded, X-Forwarded-Host, X-Forwarded-Proto, or an external URL prefix; do not use those untrusted headers to decide whether cookies are secure either.

Load and validate all application settings once at startup, before StaticAssets.load, route assembly, and Server.serve. Missing secrets, invalid ports, and absent configured assets should stop the process rather than leave a partially configured instance serving traffic.

Scalive supplies no central setting for health routes, cluster membership, shared LiveView state, or transport fallback. Add endpoint-level HTTP instrumentation as application middleware and use LifecycleObserver for LiveView operations. Scalive supports WebSocket transport only; deployment and scaling consequences are covered in Deployment.