Radiator Server Documentation — v10.34.1

management

The management clause configures the built-in management interface that exposes operational and configuration management capabilities over HTTP or HTTPS. This includes the REST API and the optional web UI.

management {
    http {
        listen {
            protocol tls;
            addr "127.0.0.1:8443";

            tls {
                certificate "MGMT_CERT";
                certificate_key "MGMT_KEY";
                require_client_certificate false;
            }
        }
        clients "MGMT_CLIENTS";
        policy "MANAGEMENT";
    }
}

Keep the management interface restricted (bind to 127.0.0.1 or a dedicated administrative network segment, and use TLS in production).

Session Timeouts

Use session-timeout and maximum-session-timeout inside the http block to control authenticated Radiator UI and Management API sessions.

management {
    http {
        session-timeout 30m;
        maximum-session-timeout 8h;

        # ...
    }
}
StatementDefaultDescription
session-timeout1hSets the rolling session lifetime. Login and each successful refresh extend the session by this duration.
maximum-session-timeoutNot setSets the maximum lifetime from the original login. Refresh cannot extend the session beyond this boundary.

Both statements accept duration values greater than zero. If maximum-session-timeout is shorter than session-timeout, the maximum timeout expires the session first.

Radiator UI refreshes its session only after trusted user input, such as a click, keyboard input, pointer input, scrolling, or editing a field. Continuous activity is combined into a bounded refresh cadence. Merely leaving a tab open does not keep the session active.

When the UI loads, regains focus, becomes visible, or resumes, it checks the server-side expiration without extending it. This means that returning from system sleep exposes an expired session instead of reviving it. Tabs for the same Radiator UI origin share one browser cookie and coordinate successful refreshes, so activity in one tab keeps the shared session active without every tab sending its own refresh request. The maximum timeout still uses the original login time and cannot be reset by activity in any tab.

When a visible tab is within five minutes of its effective expiration, the UI warns the user. A rolling inactivity warning offers an Extend session action. If the configured maximum timeout is the limiting boundary, the warning instead asks the user to save their work and sign in again because activity cannot extend that deadline.

Listener Configuration

Each listen block controls where the management interface binds. Add an addr statement for each IP address and port. One block can contain addresses from both IP families and addresses with different ports. All addresses in the block use the same protocol, TLS settings, and socket options.

StatementValuesDescription
protocoltcp, tlsUse tls for encrypted management.
addrIPv4:port or [IPv6]:portBind endpoint. Repeat for each address and port.
portInteger (1-65535)Port for the separate ip syntax.
ipIPv4 or IPv6 addressBind address for the separate port syntax.

Prefer addr when configuring multiple ports because each line contains one complete endpoint. A block can also combine repeated addr statements with a complete ip and port group. Each addr keeps its own port, while all ip statements use the separate port. For compatibility, one addr statement can be combined with additional ip statements without a separate port. In that form, the additional IP addresses use the port from addr.

The following example serves HTTPS on ports 8443 and 9443 over both IPv4 and IPv6:

management {
    http {
        listen {
            protocol tls;
            addr "0.0.0.0:8443";
            addr "[::]:8443";
            addr "0.0.0.0:9443";
            addr "[::]:9443";

            tls {
                certificate "MGMT_CERT";
                certificate_key "MGMT_KEY";
                require_client_certificate false;
            }
        }
    }
}

IP Access Control

The clients statement inside the http block references a named HTTP client list defined in the top-level clients clause. When set, only connections from matching IP addresses are accepted. Connections from unlisted addresses are rejected at the TCP level — the connection is dropped without sending an HTTP response.

The clients filter is an application-level control and not a substitute for network-level security. Use a firewall rule to restrict access to the management port as the primary defense, and treat clients as an additional layer.

clients {
    http "MGMT_CLIENTS" {
        client "admin-network" {
            source {
                ip 192.168.1.0/24;
                ip 10.0.0.0/8;
            }
        }

        client "localhost" {
            source {
                ip 127.0.0.1;
                ip ::1;
            }
        }
    }
}

management {
    http {
        clients "MGMT_CLIENTS";
        # ...
    }
}

TLS

To serve HTTPS:

  1. Set protocol tls in the listen block.
  2. Add a tls block inside listen referencing a certificate and key defined in the global certificates clause.

Certificate and key files can be uploaded individually or as part of a configuration package — see Configuration Import and Export.

listen {
    protocol tls;
    addr "127.0.0.1:8443";

    tls {
        certificate "MGMT_CERT";
        certificate_key "MGMT_KEY";
        require_client_certificate false;
    }
}

Disabling Features

Use no statements inside the management block to disable specific features.

StatementEffect
no http;Disables the entire HTTP management interface (API and web UI).
no ui;Disables the web UI while keeping the HTTP REST API active.
management {
    no ui;
    http {
        # ...
    }
}

Privilege Model

Each authenticated user is assigned a privilege level that determines which API endpoints and UI operations they can access. Privileges are hierarchical -- a higher level includes all capabilities of lower levels.

PrivilegeCapabilities
noneNo authenticated access. Health check endpoints do not require credentials.
monitorView statistics, metrics, logs, and runtime status.
readAll monitor capabilities plus view configurations.
writeAll read capabilities plus modify configurations and server state.
allFull access. Prefer this over write for administrators.

If an endpoint requires higher privilege than provided, the request is rejected with a 403 response.

For a detailed breakdown of each privilege level and which API endpoints they control, see Management API Privileges.

Management Authentication Policies

Authentication and authorization are handled by an AAA policy referenced with the policy statement inside the http block, see execution pipelines for details.

  1. A management HTTP request arrives (API call or web UI login).
  2. The policy's conditions block matches on http.management == true.
  3. The handler's @execute block runs the authentication logic:
    • Look up the user in a backend (SQL, LDAP, HTTP, JSON file).
    • Set user.privilege based on backend data or custom rules.
    • Call http-management-authentication to verify credentials against an existing session cookie or HTTP Basic Auth header.
  4. On success, the request proceeds. On failure, a 401 or 403 response is returned.

http-management-authentication Action

This built-in action handles HTTP Basic Auth and cookie-based sessions:

  • If an Authorization: Basic header is present, it verifies the submitted password against user.password in the AAA context. The backend query must have populated user.password before this action runs — the same requirement as pap.
  • If no basic auth header is present but a session cookie exists, it validates the session directly against the session store. The stored username is propagated into user.username if it is not already set. No prior backend lookup is required for session validation.
  • This action does not create session cookies. Session lifecycle (login, refresh, logout) is handled by the /auth/login and related endpoints.

Use this action inside an until accept block to try session auth before falling back to a backend bind or other authentication method.

Example: JSON File Authentication

Authenticate management users against a JSON file. The backend query maps user.username, user.password, and user.privilege from the file.

backends {
    jsonfile "MGMT_USERS" {
        filename "users.json";

        query "FIND_USER" {
            mapping {
                user.username = doc | jsonpath("$.users[?(@.username == '%{aaa.identity}')].username");
                user.password = doc | jsonpath("$.users[?(@.username == '%{aaa.identity}')].password");
                user.privilege = doc | jsonpath("$.users[?(@.username == '%{aaa.identity}')].privilege");
            }
        }
    }
}

aaa {
    policy "MANAGEMENT" {
        conditions all {
            http.management == true;
        }

        handler "AUTHENTICATION" {
            @execute {
                backend {
                    name "MGMT_USERS";
                    query "FIND_USER";
                }

                http-management-authentication;
            }
        }
    }
}

The JSON file must contain user objects with username, password, and privilege fields. See Password Hashing for supported hash formats.

Example: LDAP Authentication

Authenticate management users against an LDAP directory. A single search retrieves the user's DN and all group memberships in one round-trip. Privilege is then assigned in the policy based on whether the admin group DN appears in vars.member_of.

backends {
    ldap "MGMT_LDAP" {
        server "ldap-server" {
            url "ldaps://ldap.example.com/";
            timeout 3s;
            authentication {
                dn "cn=radiator-svc,ou=service-accounts,dc=example,dc=org";
                password "servicepassword";
            }
        }

        # Find the user and collect all group memberships in a single search.
        search "FIND_USER" {
            base "ou=people,dc=example,dc=org";
            scope sub;
            filter "(&(uid=%{aaa.identity})(objectClass=inetOrgPerson))";

            mapping {
                vars.dn = entry::dn;
                user.username = uid;
                vars.member_of += memberOf;
            }
        }

        bind "BIND_USER" {
            dn vars.dn;
            password http.authorization.password;
        }
    }
}

aaa {
    policy "MANAGEMENT" {
        conditions all {
            http.management == true;
        }

        handler "AUTHENTICATION" {
            @execute {
                backend {
                    name "MGMT_LDAP";
                    query "FIND_USER";
                }

                # Check group membership and assign privilege.
                # vars.member_of is multi-valued; == matches if any item is an exact match.
                # Default to monitor: avoids exposing configurations
                # that may contain credentials to non-admin users.
                if any {
                    vars.member_of == "CN=radiator-admins,OU=groups,DC=example,DC=org";
                } then {
                    modify { user.privilege = "all"; }
                } else {
                    modify { user.privilege = "monitor"; }
                }

                until accept {
                    # Session auth: validates the cookie directly — no additional LDAP lookup for
                    # validation; earlier LDAP queries may still be used to populate attributes/privileges.
                    http-management-authentication;
                    # Basic auth fallback: bind to LDAP with the submitted password.
                    backend {
                        name "MGMT_LDAP";
                        query "BIND_USER";
                    }
                }
            }
        }
    }
}

vars.member_of += memberOf accumulates all values of the multi-valued memberOf attribute into a list. The == condition checks whether any item in the list matches the admin group DN exactly, including the full OU path. The comparison is case-sensitive, so the DN in the condition must match the case returned by the LDAP server.

Active Directory note: AD does not populate the uid attribute by default. When connecting to an AD domain controller, replace both occurrences of uid with sAMAccountName:

filter "(&(sAMAccountName=%{aaa.identity})(objectClass=user))";
mapping {
    vars.dn = entry::dn;
    user.username = sAMAccountName;
    vars.member_of += memberOf;
}

Without user.username = sAMAccountName, the mapping leaves user.username empty. Login (POST /api/v1/auth/login) will return an error indicating that user.username is empty — check the server log for the exact attribute name to use.

Audit Logging

Add audit logging to management authentication using the @final-execute block.

handler "AUTHENTICATION" {
    @execute {
        # ... authentication logic ...
    }

    @final-execute {
        log "MANAGEMENT" {
            json {
                "User-Name" aaa.identity;
                "Reason" aaa.reason;
                "Result" "%{aaa.result}";
                "Method" http.method;
                "Path" http.path;
                "Code" http.status;
                "Ip" http.client.ip;
            }
        }
    }
}

Legacy: Credentials Block

The credentials block is supported for backward compatibility. For production deployments, use policy-based authentication instead.

When policy is not set, the management interface falls back to the credentials block. It supports static user definitions and backend references directly inside the http block.

management {
    http {
        listen {
            protocol tls;
            addr "127.0.0.1:8443";

            tls {
                certificate "MGMT_CERT";
                certificate_key "MGMT_KEY";
                require_client_certificate false;
            }
        }

        credentials {
            user "admin" {
                password "{argon2}$argon2id$v=19$m=65536,t=3,p=4$c29tZXNhbHQ$RdescudvJCsgt3ub+b+dWRWJTmaaJObG";
                privilege all;
            }
            user "monitor" {
                password "{argon2}$argon2id$v=19$m=65536,t=3,p=4$c29tZXNhbHQ$RdescudvJCsgt3ub+b+dWRWJTmaaJObG";
                privilege monitor;
            }
        }
    }
}

Each user block requires password and privilege (any privilege level from the Privilege Model above; use all for administrators). Passwords can be plain text or hashed with {argon2} or {crypt-sha256} prefixes — argon2 is recommended. See Password Hashing for how to generate hashes.

Optional Static Users

Set omit-if-password-empty true on a static user to omit that user when its password expression resolves to an empty string while loading the configuration. This is useful for optional accounts whose passwords come from environment variables:

credentials {
    user "monitor" {
        omit-if-password-empty true;
        password env.MONITOR_PASSWORD | default("");
        privilege monitor;
    }
}

When MONITOR_PASSWORD is unset or empty, the monitor user is not added and cannot log in. When it contains a value, the user is added and that value is used as its password; use a supported prefixed password hash for deployments. The statement defaults to false; without it, an empty password retains the existing static-user behaviour. It does not omit a user whose password is non-empty, and it does not enforce password strength or a minimum password length.

Authentication Order

For each incoming request, the credentials block authenticates as follows:

  1. Session cookie — if a valid session cookie is present and matches the username, the request is accepted immediately without checking credentials.
  2. Static users — the username from the Authorization: Basic header is looked up in the user blocks. If a matching entry is found, the password is verified. If it matches, the request is accepted with that user's privilege.
  3. Backends — only reached if no matching static user was found. Backends are queried in alphabetical order by name. The first backend that returns a user with a non-empty username and a password is used to verify the submitted password. Remaining backends are not queried once a match is found.

If none of the above steps succeed, the request is rejected with a 401 response.

Session cookies use the HttpOnly and SameSite=Strict attributes. Browsers do not send these cookies when a request originates from another site. Cookies sent by a TLS management listener also use the Secure attribute. Each listener uses its own transport policy when the same management service has both HTTP and HTTPS listeners.

Set secure_session_cookie true; in the management.http block when a reverse proxy terminates HTTPS and connects to Radiator over HTTP. This setting forces login, refresh, and logout cookies to use Secure on every listener. The default is false, so HTTP-only deployments continue to work.

management {
    http {
        listen {
            protocol tcp;
            addr "127.0.0.1:8080";
        }

        # The reverse proxy exposes this listener through HTTPS.
        secure_session_cookie true;
        policy "MANAGEMENT";
    }
}