Shared Signals Framework
Shared Signals Framework (SSF)
Section titled “Shared Signals Framework (SSF)”Standards
Section titled “Standards”- OpenID Shared Signals Framework 1.0
- OpenID Continuous Access Evaluation Profile (CAEP) 1.0
- OpenID RISC Profile Specification 1.0
- RFC 8417 (SET), RFC 8935 (push), RFC 8936 (poll)
Run Surface
Section titled “Run Surface”SSF is a durable session in Looking Glass: /looking-glass?protocol=ssf. Catalog flow IDs are presets into one Looking Glass session (they fill the event/delivery chrome). They do not replace the chrome.
- Fire event encodes and delivers a CAEP/RISC SET for the selected subject to every enabled stream that requested that event type (the Looking Glass lab stream and any Stream Management poll/push Receivers). That is the only Looking Glass control that mutates RP account state. Verify stream reads transmitter metadata and POSTs
/verify; it does not revoke sessions or disable accounts.
SSF remains its own image (protocolsoup-ssf) behind the gateway, the same way SCIM does. RP security state is stored on the SSF service. After a verified CAEP session-revoked SET, the receiver also POSTs to federation over HTTP so Alice/Bob OAuth sessions actually die.
/ssf-sandbox redirects to Looking Glass.
Available Flows
Section titled “Available Flows”Looking Glass hides the per-event action dropdown. The chrome (subject, event, push/poll) is the control surface. Catalog IDs below still work as deep-link presets (/looking-glass?protocol=ssf&flow=caep-session-revoked).
| Flow ID | Name | Looking Glass role |
|---|---|---|
ssf-stream-lab |
Looking Glass session | Default durable session |
ssf-stream-configuration |
Stream Configuration | Preset: use Verify stream (does not change RP state) |
ssf-push-delivery |
Push Delivery | Preset: delivery = RFC 8935, then Fire event |
ssf-poll-delivery |
Poll Delivery | Preset: delivery = RFC 8936, then Fire event |
caep-session-revoked |
Session Revoked (CAEP §3.1) | Preset: event = session-revoked, then Fire event |
caep-credential-change |
Credential Change (CAEP §3.3) | Preset: event = credential-change, then Fire event |
risc-account-disabled |
Account Disabled (RISC §2.3) | Preset: event = account-disabled, then Fire event |
risc-credential-compromise |
Credential Compromise (RISC §2.7) | Preset: event = credential-compromise, then Fire event |
Demo Scenarios
Section titled “Demo Scenarios”- SSF in Looking Glass – Durable Looking Glass session for CAEP/RISC events
- Session Revocation Demo – CAEP session revoked event lifecycle
- Credential Compromise Response – RISC response action execution
- Push vs Poll Comparison – Delivery mode behavior comparison
Supported Event Actions
Section titled “Supported Event Actions”session-revoked, credential-change, device-compliance-change, credential-compromise, account-disabled, account-enabled, account-purged, identifier-changed, assurance-level-change, token-claims-change, identifier-recycled, account-credential-change-required
The lab action sessions-revoked maps to CAEP session-revoked (all sessions). RISC sessions-revoked is not emitted (RISC §2.11).
Endpoints
Section titled “Endpoints”Transmitter
Section titled “Transmitter”| Path | Methods | Purpose |
|---|---|---|
/.well-known/ssf-configuration |
GET | SSF discovery (issuer insertion, SSF §7.2) |
/ssf/jwks |
GET | Transmitter JWKS |
/ssf/stream |
POST, GET, PUT, PATCH, DELETE | Stream CRUD (GET without stream_id returns that Receiver’s list; PUT replaces Receiver-Supplied properties; nested delivery) |
/ssf/status |
GET, POST | Stream status (stream_id required; body includes stream_id) |
/ssf/verify |
POST | Stream verification (stream_id required; state optional; 204 empty) |
/ssf/subjects |
GET | Looking Glass demo identities |
/ssf/subjects/add |
POST | Add Subject (stream_id + RFC 9493 subject; 200 empty) |
/ssf/subjects/remove |
POST | Remove Subject (stream_id + RFC 9493 subject; 204) |
/ssf/actions/{action} |
POST | Trigger event action (fan-out to eligible streams) |
/ssf/poll/{stream_id} |
POST | Poll delivery (RFC 8936). URL is Transmitter-supplied on the stream. |
Receiver
Section titled “Receiver”| Path | Methods | Purpose |
|---|---|---|
/ssf/receiver/push |
POST | Receive pushed SETs |
/ssf/receiver/status |
GET | Receiver health |
/ssf/receiver/events |
GET | Received event log |
/ssf/receiver/actions |
GET | Response action log |
Monitoring
Section titled “Monitoring”| Path | Methods | Purpose |
|---|---|---|
/ssf/events |
GET | Event history |
/ssf/security-state |
GET | All security states |
/ssf/security-state/{email} |
GET | State by subject |
/ssf/security-state/{email}/reset |
POST | Reset RP posture |
/ssf/decode |
POST | Decode SET |
Architecture
Section titled “Architecture”SSF runs as protocolsoup-ssf (cmd/server-ssf) with a standalone receiver on port 8081 alongside the main API on port 8080. Push delivery to {baseURL}/ssf/receiver/push is proxied to the internal receiver and returns 202. The receiver validates SETs and executes response actions via ReceiverActionExecutor on this service. After a verified CAEP session-revoked SET it POSTs { "email": "[email protected]" } to FEDERATION_SERVICE_URL/oauth2/demo/caep/revoke-subject (bearer SSF_TO_FEDERATION_TOKEN) so MockIdP sessions and tokens die. That hop is RP policy, not an SSF SET field, and is shown on the Looking Glass bus.
Do not register SSF in the federation binary. Cross-service CAEP is HTTP only (loopback on the Fly/cmd/server monolith).
Local/demo issuer may be http:// (SSF §7.1 wants https). Same lab TLS story as other ProtocolSoup services.
What To Validate
Section titled “What To Validate”- Stream configuration: nested
delivery: { method, endpoint_url },events_supportedvsevents_delivered - Discovery:
GET /.well-known/ssf-configuration,spec_version"1_0",issueridentical to SETiss,authorization_schemesincludesurn:ietf:rfc:6749,default_subjects"ALL" - Stream management is
stream_idaddressed.GET /ssf/streamwithoutstream_idreturns that Receiver’s list ([]when none). Create is 201. Delete is 204. - Stream Management is an OAuth 2.0 resource server when
SSF_AS_JWKS_URIis set:ssf.read/ssf.manage, bearer header only (no queryaccess_token). The Transmitter also checks revocation status (MockIdP on the monolith, orSSF_AS_INTROSPECT_URIon the split SSF image). The federation AS seeds confidential clientssf-stream-clientfor those scopes (GET /oauth2/demo/clients). - SET structure:
iss,iat,jti,aud,events(exactly one event), top-levelsub_id, no JWTsuborexp,typ=secevent+jwt, RS256 - Push delivery:
Content-Type: application/secevent+jwt, signature, 202 (not 200); push URL is the Receiver’sdelivery.endpoint_url - Poll delivery: POST to the stream’s Transmitter-supplied
delivery.endpoint_url(/ssf/poll/{stream_id});setsmap keyed byjti; unacknowledged SETs retransmit;maxEvents: 0is ack-only;acks/setErrson the next poll - Subject Management:
POST /ssf/subjects/add(200) andPOST /ssf/subjects/remove(204) withstream_id+ RFC 9493subject.default_subjectsisALL; remove excludes that subject from transmission. - Device Compliance: CAEP
device-compliance-changeSETs use a Complexsub_id(user+device) andreason_admin. The Receiver restricts RP access whencurrent_statusisnot-compliant. - Verification:
stream_idrequired, 204 empty, verification SETsub_idopaque stream id;stateechoed only when supplied - CAEP/RISC members:
namespace+current_level;credential_type;not-compliant; RISCreasononlyhijacking|bulk-account - Stream Management tokens: signature, expiry,
iss/aud/scope, and RFC 7009 revocation status (in-process MockIdP or RFC 7662 introspection) - Looking Glass Flow tab is the Looking Glass bus only (no executor-local spoof timeline)