AxonFlow v9.16.0 Release Notes
v9.16.0 completes browser SSO for the customer portal: interactive OIDC login now works end-to-end, alongside the SAML login that shipped in v9.15.0. A tenant that already uses OIDC for per-user fleet tokens can now drive portal login from the same configuration, without adding a second identity-provider application. The release also hardens every OIDC identity-provider endpoint fetch against server-side request forgery, and fixes an SSO login failure on direct connections.
It is a MINOR by the semver policy: it adds a new backward-compatible capability (OIDC portal login) and hardens a fetch path; it removes nothing. It introduces one opt-in environment variable (AXONFLOW_OIDC_ALLOW_PRIVATE) that internal-identity-provider deployments must set. The one new migration is additive.
Am I affected?
Deployments that want browser portal login through an OIDC identity provider get the new interactive OIDC login. If you use OIDC for per-user fleet identity today, this is the recommended way to add portal login (see below).
Any deployment that fetches OIDC identity-provider endpoints (per-user fleet OIDC tokens, or the new OIDC portal login) gets the SSRF hardening. If your identity provider runs on a private network, you must set AXONFLOW_OIDC_ALLOW_PRIVATE=true after upgrading.
Deployments using interactive SSO login (SAML or OIDC) without a load balancer that sets X-Forwarded-For get the login-500 fix.
Everyone else: routine upgrade. The one migration is additive and no-ops where it does not apply.
Interactive OIDC portal login
The portal now supports a full browser OIDC authorization-code login, alongside SAML. It discovers the authorize and token endpoints from the configured issuer, redirects to the identity provider with the tenant client ID and a redirect URI derived from SSO_BASE_URL, and on callback validates a signed state (CSRF) and nonce (replay), exchanges the code, and verifies the id_token signature against the provider JWKS before establishing the session.
A tenant has a single SSO configuration, and it is either SAML or OIDC. Per-user fleet identity requires that configuration to be OIDC. So a tenant that wants both browser portal login and per-user fleet tokens must use OIDC for portal login: one OIDC configuration drives both. Configuring a SAML portal login on such a tenant would replace the OIDC configuration and disable fleet identity. To add portal login to a fleet-OIDC tenant, extend the existing OIDC configuration with a portal client_id and client_secret. See the JumpCloud integration guide and SSO configuration.
Configuring OIDC portal login adds oidc_client_id and oidc_client_secret to the SSO configuration (migration core/158, additive). The client secret is stored with the same at-rest posture as the SAML signing key: a dedicated column under the same organization isolation, never returned in an API response, never logged.
OIDC identity-provider endpoint fetches are SSRF-hardened
All OIDC identity-provider endpoint fetches (discovery, JWKS, token exchange) now validate the resolved IP at connection time and block redirects that would reach an internal or cloud-metadata address, closing a redirect-follow and DNS-rebinding gap.
By default the hardening blocks identity-provider hosts that resolve to a private address (RFC-1918, CGNAT, link-local, or a Kubernetes ClusterIP / *.svc.cluster.local). If your OIDC provider runs inside your own network (an internal Keycloak, ADFS, or PingFederate), set AXONFLOW_OIDC_ALLOW_PRIVATE=true on the agent and customer-portal after upgrading, or every OIDC fetch fails closed. A blocked fetch logs at ERROR naming the IP and this variable. Public identity-provider (SaaS) deployments need no change.
SSO login no longer fails on a direct connection
Both the SAML and OIDC portal-login callbacks recorded the session with the request's raw remote address, which includes a port and was rejected by the session store's IP column, so a login without an X-Forwarded-For header (a direct connection, rather than one behind a load balancer that strips the port) failed. Both callbacks now normalize the address the same way password login does. If your SAML login worked behind a load balancer but failed on a direct connection, this is the fix.
Compliance report exports require artifact storage on self-hosted deployments
The compliance posture and readiness dashboards work with no extra configuration. Generating a report and downloading its PDF, CSV, or XLSX additionally requires an S3-compatible object store: the orchestrator writes the artifact there and hands the portal a presigned URL. The self-hosted install bundle now exposes an AUDIT_EXPORT_* configuration block on the orchestrator; set it to your own durable, in-region bucket to enable exports. An in-region bucket keeps compliance evidence in jurisdiction. Left unset, dashboards still render but report generation reports that no artifact storage backend is configured. This is configuration only, no migration. See the AUDIT_EXPORT_* block in the bundle's .env.example.
Before you upgrade
- One additive migration (
core/158) adds two optional columns used by OIDC portal login; it no-ops on deployments without the SSO configuration table. - If your OIDC identity provider is on a private network: set
AXONFLOW_OIDC_ALLOW_PRIVATE=trueon the agent and customer-portal. - If you use OIDC for fleet identity and want portal login: extend your existing OIDC configuration with portal client credentials rather than adding a SAML application. See the JumpCloud integration guide.
- If you use compliance report exports: configure the
AUDIT_EXPORT_*block (see.env.example) to point at your own in-region object store.
SDK and plugin compatibility
No SDK or plugin changes are required. Clients compatible with v9.15.x are compatible with v9.16.0.
