Listeners and hosted applications
iya-sts answers every HTTP protocol, the admin console, the management API and
the user portal on one port, the main port (global.port), unless you say
otherwise. You can define custom listeners — more HTTPS ports, each with
its own address, certificate, TLS policy and client authentication — and say
which hosted application each one answers. An application can be on
several listeners at once.
Two common uses:
- The sign-in service behind mutual TLS. A listener that requires a client
certificate, with
authnon it, so every sign-in starts with a verified certificate. - The console and the management API off the main port. A listener on an
internal address, with
admin-consoleandmanagement-apion it alone, so the main port — the one the internet reaches — does not answer them.
Everything is on Server configuration → Listeners in the console, and on
GET /admin-api/listeners and POST /admin-api/listeners/{action}.
The hosted applications
A path belongs to exactly one application. The list is fixed; you map the applications, you do not define them. Listeners → Applications shows each one, the paths it answers and where it is.
| Application | What it is |
|---|---|
home |
GET /, the documentation, terms and policy pages, the realm list |
authn |
The sign-in service, its second factors, the wallet, SPNEGO and certificate sign-ins (/tls/sign-in), and /logout |
portal |
The user portal |
report |
Reports at /report, and /report-api |
admin-console |
The admin console, /admin |
management-api |
/admin-api |
oauth-oidc |
The authorization server and OpenID provider, their discovery documents, the access-token status list |
saml2, saml11, ws-trust, ws-federation |
The SAML, WS-Trust and WS-Federation identity providers |
federation, oidfed |
Federation relationships, and OpenID Federation |
oid4vc |
OpenID4VCI, OpenID4VP, DIDs and the W3C VC API |
scim, ssf, gnap, xacml |
SCIM, Shared Signals, GNAP, XACML |
acme, est, scep, pki |
Certificate enrollment, and the certificate authority’s public documents |
kerberos, spiffe, tls, devices |
MS-KKDCP and SPNEGO pages, the SPIFFE bundle, the TLS views, the device test control |
/healthcheck is no application’s: every listener answers it, for the load
balancer in front of it.
Defining a listener
A listener is a JSON object:
{
"id": "admin",
"port": 9443,
"publicBaseUrl": "https://admin.internal.example.com:9443",
"hostnames": ["admin.internal.example.com"],
"certificateFile": "/run/certs/admin.pem",
"privateKeyFile": "/run/certs/admin.key",
"clientAuth": "required",
"tls": { "pqcOnly": "on" }
}
| Member | |
|---|---|
id |
Lower-case letters, digits and hyphens, from a letter; one name in the whole service. main is the main port. |
port |
Bound on every node: put your own load balancer in front of it. It may not be another listener’s or one of the service’s own sockets. |
publicBaseUrl |
The https origin the listener is reached at, with no path. Every URL of an application advertised on this listener is built on it. |
hostnames |
The DNS names an issued certificate carries; the host of publicBaseUrl when left out. |
certificateFile, privateKeyFile |
Your certificate (a public CA’s for a browser-facing listener) and its key — both or neither. Without them the owning realm’s certificate authority issues one for hostnames and renews it; a client must trust the service’s Root to accept it. |
clientAuth |
none (no CertificateRequest), optional (asked, not required — the default, as on the main port) or required (a handshake without a certificate chaining to the client truststore is refused). |
tls |
The listener’s own TLS settings, by the short names the main port’s per-listener rows use: minVersion, disableTls12, ciphers, tls13CipherSuites, pqcOnly, groups, signatureAlgorithms, trustAnchorsFile, trustIssuedClientCertificates, sessionTimeoutS, sessionCacheSize, keepAliveTimeoutS, headersTimeoutS, maxRequestsPerSocket, maxConnections, http2 (true, false, on or off), http2MaxConcurrentStreams. A value left out, inherit, "" or -1 follows the service-wide setting. |
The service’s listeners are listeners.custom (in the default realm) and
answer every realm under its /realm/<id> prefix. A realm’s own listeners
are listeners.realm, set on that realm, and answer that realm’s paths alone —
the default realm’s or another realm’s is a 404 there.
A change binds, rebinds or closes the listener on every node at once; a change
of clientAuth or tls is applied at the next handshake without dropping a
connection. A listener that cannot bind (the port in use, a certificate file
that cannot be read) is shown as failed on the Listeners page and never stops
the service.
Mapping applications to listeners
listeners.applications is a JSON object from an application id — or *,
every application not named — to the listeners that answer it and the one it
is advertised on:
{
"admin-console": { "listeners": ["admin"] },
"management-api": { "listeners": ["admin"] },
"authn": { "listeners": ["main", "mtls"], "advertised": "mtls" }
}
- A path of an application is answered only on the listeners it is on.
On any other it is a 404 that names where the application is
(
STS-TLS-0047in the log). - An application the mapping does not name is on
mainalone, so an empty mapping is the service as it always was. advertised(the first listener when left out) is where the application’s URLs are built: its issuer, metadata, redirects, mailed links. One URL per endpoint is published. Where a specification has a place for another address, the other listeners are published there too: anoauth-oidclistener asking for a client certificate is the metadata’s RFC 8705mtls_endpoint_aliases, and SAML 2.0’s metadata lists a secondSingleSignOnServiceandSingleLogoutServiceLocation for each othersaml2listener.- A link or redirect from one application to another that is not on the same
listener — the authorization endpoint sending a browser to
/authn/login, the console calling/oauth2/tokenand/admin-api— is made absolute on the other application’s advertised base. The console’s page is allowed to call those origins. -
Per realm. A realm’s own
listeners.applicationsis read entry by entry before the service’s: its entry for an application, then its*, then the service’s entry, then the service’s*. A realm says only what differs. To serve a whole realm on its own listener (what a realm’s own listener was before), map*to it — besidemainto keep the main port answering too:{ "*": { "listeners": ["main", "acme-front"], "advertised": "acme-front" } }
Changing where an application is advertised changes its URLs. For
oauth-oidc that is its issuer: every client’s discovery and every token
names the old one. oidfed must be on the listener oauth-oidc is advertised
on, because a realm’s Entity Identifier is its issuer.
The sign-on session across host names
The sign-in service, the authorization server, the SAML, WS-Federation and federation identity providers, GNAP’s interaction and the portal all read one sign-on session cookie. It is host-only by default, which is the stronger setting: different ports on one host name share it, different host names do not.
A mapping that puts those applications on listeners with different host names
is refused (STS-CORE-0155) unless authn.cookieDomain names a domain every
one of them is under — example.com for auth.example.com and
portal.example.com.
Warning. With
authn.cookieDomainset, every host under that domain is sent the session cookie, including hosts this service does not run. Set it to the narrowest domain your listeners share, never to a domain other parties host under. Setwebauthn.rpIdto the same domain, or a passkey registered on one host is not usable on another; the Listeners page warns when it is not.
Not locking yourself out
- A change that takes
management-apioff the listener the request making it arrived on is refused (STS-CORE-0156) unless it says"confirm": true(POST /admin-api/listeners/set-applications, or the checkbox on the page). listeners.adminOnMain=true(STS_LISTENERS_ADMIN_ON_MAIN=true), set in the environment or the appconfig file and applied at the next start, puts the console and the management API back on the main port and advertises them there, whatever the mapping says. No write can turn it off.- A listener a mapping names cannot be removed until the mapping no longer names it.
The management API
GET /admin-api/listeners
POST /admin-api/listeners/set-listeners {"value": [ ...listeners... ]}
POST /admin-api/listeners/set-applications {"value": { ...mapping... }, "confirm": true}
Both writes act in the realm the call is made in (/realm/<id>/admin-api/...):
the service’s listeners and mapping in the default realm, the realm’s own in
any other. An empty value means none. The operations are in
GET /admin-api/openapi.json.
Not supported
- Custom listeners while the service runs as several cells (
STS-CORE-0148). - The embedded protocol debugger, LDAP and LDAPS, the KDC, SPIFFE’s gRPC listeners and the channel between cells are listeners of their own protocols, with their own settings on the Listeners page; they answer no hosted application and are not mapped.
- An application advertised on the main port while a request arrives on a
custom listener builds its URLs on that request’s host name and the main
port. Set
global.publicBaseUrlto say the main port’s address outright.