# Shared Signals from Okta or Entra

> When your identity provider disables an account, revokes a session or flags a compromised credential, the agents acting for that person stop within seconds, under a security hold.

Source: https://immiscible.fly.dev/docs/guides/shared-signals

An agent acts for a person. When that person's identity is in doubt, their agents should not carry on as if nothing happened. Immiscible is a receiver for the OpenID **Shared Signals Framework** (SSF), the standard Okta, Microsoft Entra and others use to push security events, delivered as Security Event Tokens (SETs) by RFC 8935 push.

## What it acts on

| Event | Effect |
|---|---|
| CAEP `session-revoked` | freeze the person's agents |
| CAEP `credential-change` | freeze |
| CAEP `token-claims-change` | freeze |
| CAEP `assurance-level-change` | freeze, unless the level went up, which is recorded and not acted on |
| RISC `account-disabled`, `account-purged` | freeze, and mark agents they sponsored for others as orphaned |
| RISC `credential-compromise` | freeze |

The subject's own agents are frozen under a **security hold**, so a person decides when they start again. Where the person who left was the sponsor or kill owner of **someone else's** agents, those are not frozen (that would punish their own principal for a colleague leaving) but are marked orphaned, recorded, and their owners told: an agent nobody answers for is a gap to close.

Events are subject to the machine freeze ceilings: a transmitter that suddenly reports thousands of people leaves the excess waiting for a person. See [the kill switch](https://immiscible.fly.dev/docs/guides/kill-switch.md#ceilings-on-machines).

## 1. Configure the transmitter in Immiscible

An owner saves the transmitter's issuer and keys:

```bash
curl -X PUT "https://immiscible.fly.dev/api/w/$IMMISCIBLE_WORKSPACE/ssf/transmitter" \
  -H "cookie: __Host-sid=$IMMISCIBLE_SESSION" -H "x-immiscible-csrf: 1" \
  -H "content-type: application/json" \
  -d '{ "issuer": "https://acme.okta.com", "jwksUrl": "https://acme.okta.com/oauth2/v1/keys" }'
```

| Field | Meaning |
|---|---|
| `issuer` | the `iss` your provider puts in its SETs, exactly |
| `jwksUrl` or `jwks` | where its signing keys are, or the keys inline |
| `audience` | optional; defaults to the receiver URL below |

The answer includes the **receiver endpoint** to give your provider: `https://immiscible.fly.dev/ssf/<workspace id>/events`.

## 2. Point the provider at it

In your provider's Shared Signals settings (Okta and Microsoft Entra both transmit CAEP and RISC events), add a receiver stream with the endpoint above, **push** delivery, and the events in the table. Any transmitter that pushes signed SETs works the same way.

## What is checked

The body is `application/secevent+jwt`. Only **ES256** and **RS256** are accepted. Issuer, audience, freshness and replay are checked: each SET must carry a `jti`, and exactly one delivery of a `jti` is ever acted on (a repeat is refused as `invalid_request`). Errors come back in RFC 8935's JSON shape and never say whether a workspace exists.

## Matching people

The SET's subject is matched to members of the workspace by `email` and by `iss_sub` (their single sign-on issuer and subject), including inside `aliases` and the `user` or `account` of a complex subject. A subject that matches nobody stops nothing. What a SET did (the issuer, the events, the agents frozen or marked orphaned) is recorded in the evidence ledger.
