Signaling authentication
The SSO bridge issues audience-bound data plane signaling tokens through
POST /api/oauth/token. Request grant_type=client_credentials,
scope=dplane-signaling and audience=<receiving plane identity> with the
client's usual authentication. resource is an alias for audience; if both
are supplied they must agree.
Deployment configuration authorizes each signaling client. Ordinary application
permissions do not grant signaling authority. Each client needs both a mapping
in signalingClients and the exact execute permission for its direction:
| Caller role | Required permission | Audience |
|---|---|---|
controlplane | execute:dp.transfer | Receiving data plane identity |
dataplane | execute:cp.transfer | Receiving control plane identity |
The mapping contains an explicit audience allowlist. Do not put control plane receivers in a control plane caller's allowlist, or data plane receivers in a data plane caller's allowlist. The receivers also verify the direction's permission. Broad management permissions alone do not satisfy this issuance check.
signalingClients:
- clientId: cp-tenant-a-credential
tenant: tenant-a
identity: controlplane-a
role: controlplane
audiences: [dataplane-a]
- clientId: dp-tenant-a-credential
tenant: tenant-a
identity: dataplane-a
role: dataplane
audiences: [controlplane-a]
Create the OAuth clients separately, for example through initClients, with
grants: [client_credentials] and the required permissions above. The mapping
does not create clients or assign permissions. Use a separate OAuth client for
each tenant and caller role, and keep exactly one mapping per client.
tenant is the receiving tenant's slug. identity becomes the JWT client_id
and defaults to the authenticated OAuth client ID. sub defaults to that plane
identity. An optional fixed subject overrides sub for integrations such as
Siglet, where it must equal the participant context ID in the request path.
Request parameters cannot change the configured tenant, plane identity or
subject. The azp claim retains the authenticated OAuth client ID.
signalingClients:
- clientId: cp-siglet-tenant-a-credential
tenant: tenant-a
identity: controlplane-a
subject: siglet-participant-context-a
role: controlplane
audiences: [siglet-dataplane-a]
These mappings provide signaling isolation independently of full SSO bridge
multi-tenancy. The issuer signs tokens with its persistent key set. Public keys
are available at the jwks_uri published by its OpenID metadata. Configure
receivers with that issuer, its JWKS and their own exact audience. Tokens carry
aud, sub, client_id, tenant, scope, permissions, iat, exp and
jti. Access tokens expire after one hour; client credentials grants do not
issue refresh tokens.
CLI deployments and existing installations
The deployment CLI generates one control plane OAuth alias per tenant and
auth.signalingCredentials selects that alias for each outgoing request. These
aliases reuse the control plane's existing secret or public key. Their
secretName is empty so the SSO bridge does not overwrite the base control
plane Secret with an alias client ID. Data plane clients retain their existing
OAuth credentials.
For an existing installation, preserve every data plane's registered identity
by setting its workload config.controlPlane.dataplaneId to the current
dataplaneId from the control plane registry before rendering. The CLI uses this
override for the data plane identity, callback token identity and audience
allowlist. Without an override, a fresh deployment uses the data plane OAuth
client ID. Changing a previously generated UUID to that default creates a new
registration and leaves existing transfers bound to the old registration.
SSO initClients seeds missing clients but does not overwrite the permissions
of existing clients. Add execute:cp.transfer to each existing data plane
client through the SSO management API before enabling the new callbacks.
Preserve its other permissions and credentials. The new control plane aliases
receive execute:dp.transfer when first seeded. No database reset is required.