Skip to content

Conversation

@thomasdarimont
Copy link
Contributor

@thomasdarimont thomasdarimont commented Nov 4, 2025

This PR adds initial support for Shared Signals Framework with Security Event Token (SET) Push Delivery using HTTP.

Users can manage SSF Receiver components within a realm that can be connected with a SSF Transmitter.
The SSF Transmitter can send SETs (Security Event Tokens) via HTTP Push to an endpoint exposed by the Keycloak realm. A new SsfEventListener SPI can be used to react on received SSF events from a SET.

This PR assumes SSF Streams to be registered outside of Keycloak. A SSF Receiver in Keycloak is associated with a stream by configuring the StreamId, Audience and SSF Transmitter Access token in the SSF Receiver configuration.

There can be multiple logical SSF Receivers defined within a realm that can handle SET events via a SsfEventListener.

  • Add new experimental SSF feature flag
  • Add SET parsing infrastructure
  • Add support for Subject Identifier parsing
  • Add receiver management via Identity Providers
  • Add transmitter keys management
  • Add PushEndpoint for SET PUSH Delivery
  • Add support for standard SSF Stream, CAEP and RISC events.
  • Add plugable SsfEventListener infrastructure to handle SSF events
  • Add support for handling CAEP SessionRevoked event to terminate user sessions.

Fixes #43614
Screenshot 2025-11-09 at 14 16 43
The redirect URI, client_id and client_secret will be removed later.

Screenshot 2025-11-09 at 14 19 37

Demo

ssf-keycloak-SET-push-demo.mov

Signed-off-by: Thomas Darimont [email protected]

@thomasdarimont
Copy link
Contributor Author

thomasdarimont commented Nov 4, 2025

TODOs:

  • Add tests for SET parsing / validation
  • Add user documentation

Backlog:

  • Add "link" with Identity providers to register SSF receiver if IdP can act as SSF Transmitter
  • Allow user/admin to specify interested SSF events

@thomasdarimont thomasdarimont changed the title Initial support for Shared Signals Framework Initial support for Shared Signals Framework with Push Delivery Nov 4, 2025
@thomasdarimont
Copy link
Contributor Author

thomasdarimont commented Nov 9, 2025

Usage example with caep.dev

SSF Stream setup with caep.dev

Register with https://caep.dev to obtain an SSF transmitter access token:

  1. https://caep.dev/register
  2. Provide name / email address
  3. Provide (dummy) Org data, and specify SSF Stream audience, in the example below we use https://ssf-receiver.keycloak.org
  4. Verify email
  5. Download access token

Create a SSF Stream on caep.dev

  1. https://caep.dev/transmitter/events
  2. Enter provided access token
  3. Create stream (see create a stream request)

Create a stream request with caep.dev

Use the provided access token as transmitterToken and specify your own push endpoint URL pushEndpointUrl and push auth header via pushAuthHeader.
With this PR, the pushEndpointUrl for a SSF Receiver with the alias caepdev is: $REALM_ISSUER_URL/ssf/push/caepdev.

In the following I use the Keycloak realm ssf-poc.

POST https://ssf.caep.dev/ssf/streams
Authorization: Bearer {{transmitterToken}}
Content-Type: application/json

{
  "delivery": {
    "method": "urn:ietf:rfc:8935",
    "endpoint_url": "{{pushEndpointUrl}}",
    "authorization_header": "{{pushAuthHeader}}"
  },
  "events_requested": [
    "https://schemas.openid.net/secevent/caep/event-type/session-revoked",
    "https://schemas.openid.net/secevent/caep/event-type/credential-change",
    "https://schemas.openid.net/secevent/caep/event-type/device-compliance-change",
    "https://schemas.openid.net/secevent/caep/event-type/token-claims-change",
    "https://schemas.openid.net/secevent/caep/event-type/assurance-level-change"
  ],
  "description": "This field is optional. Remove this field if not needed."
}

This will yield a 201 Created response like this:

{
  "stream_id": "5cf99a08-7dd4-4c51-9a88-ada2a9c89feb",
  "iss": "https://ssf.caep.dev/",
  "aud": "https://ssf-receiver.keycloak.org",
  "delivery": {
    "authorization_header": "...pushAuthHeader..",
    "method": "urn:ietf:rfc:8935",
    "endpoint_url": "..pushEndpointUrl.."
  },
  "events_supported": [
    "https://schemas.openid.net/secevent/caep/event-type/session-revoked",
    "https://schemas.openid.net/secevent/caep/event-type/credential-change",
    "https://schemas.openid.net/secevent/caep/event-type/device-compliance-change",
    "https://schemas.openid.net/secevent/caep/event-type/assurance-level-change",
    "https://schemas.openid.net/secevent/caep/event-type/token-claims-change",
    "https://schemas.openid.net/secevent/ssf/event-type/verification"
  ],
  "events_requested": [
    "https://schemas.openid.net/secevent/caep/event-type/session-revoked",
    "https://schemas.openid.net/secevent/caep/event-type/credential-change",
    "https://schemas.openid.net/secevent/caep/event-type/device-compliance-change",
    "https://schemas.openid.net/secevent/caep/event-type/token-claims-change",
    "https://schemas.openid.net/secevent/caep/event-type/assurance-level-change"
  ],
  "events_delivered": [
    "https://schemas.openid.net/secevent/caep/event-type/session-revoked",
    "https://schemas.openid.net/secevent/caep/event-type/credential-change",
    "https://schemas.openid.net/secevent/caep/event-type/device-compliance-change",
    "https://schemas.openid.net/secevent/caep/event-type/token-claims-change",
    "https://schemas.openid.net/secevent/caep/event-type/assurance-level-change"
  ],
  "description": "This field is optional. Remove this field if not needed."
}

Now our stream is created and we can start sending events to it. Bit first we need to create a
SSF Receiver associated with the SSF stream we just created.

Create a SSF Receiver in Keycloak

  1. In the ssf-poc Keycloak realm goto Identity Providers
  2. Click on the new SSF Receiver item (or select it from the Providers drop down list).
  3. Use the alias caepdev and SSF Receiver for caep.dev as display name (enter dummy data for clientid/secret - will be removed later)
  4. Click add
  5. Fill out the following
    Description: Test Reciever for caep.dev SSF Transmitter
    Issuer: https://ssf.caep.dev/
    Transmitter Access Token: ... the token from caep.dev
    Audience: https://ssf-receiver.keycloak.org
    StreamID: 5cf99a08-7dd4-4c51-9a88-ada2a9c89feb (from the create stream response)
    Push Authorization Header: .. (from the create stream response)

Demo

  1. Create test user with dummy email address, e.g. [email protected] and a password
  2. Sign in to the account console with that user
  3. Go to https://caep.dev/transmitter/events and enter your transmitter access token
  4. Select event type Session Revoked, Subject Type Email with the user email, e.g. [email protected].
  5. Click on Send CAEP Event and wait for a Event Pushed message.
  6. Reload the account console, the user should now be signed out.

In the server log you should see log messages like this:

2025-11-09 14:30:05,400 DEBUG [org.keycloak.protocol.ssf.receiver.transmitter.DefaultSsfTransmitterClient] (executor-thread-1) Sending transmitter metadata request. realm=ssf-poc url=https://ssf.caep.dev/.well-known/ssf-configuration
2025-11-09 14:30:05,842 DEBUG [org.keycloak.protocol.ssf.receiver.transmitter.DefaultSsfTransmitterClient] (executor-thread-1) Received transmitter metadata response. realm=ssf-poc status=200
2025-11-09 14:30:05,848 DEBUG [org.keycloak.protocol.ssf.receiver.transmitter.DefaultSsfTransmitterClient] (executor-thread-1) Stored transmitter metadata in cache. realm=ssf-poc url=https://ssf.caep.dev/.well-known/ssf-configuration
2025-11-09 14:30:06,017 DEBUG [org.keycloak.protocol.ssf.endpoint.SsfPushDeliveryResource] (executor-thread-1) Ingesting valid security event token. realm=ssf-poc receiverAlias=caepdev jti=YTBhYmRjMjktZTEyZC00NmE3LWI4Y2YtOTIxYzJkOTJlMmZj
2025-11-09 14:30:06,020 DEBUG [org.keycloak.protocol.ssf.event.processor.DefaultSsfSecurityEventProcessor] (executor-thread-1) Processing SSF events for security event token. realm=ssf-poc jti=YTBhYmRjMjktZTEyZC00NmE3LWI4Y2YtOTIxYzJkOTJlMmZj streamId=5cf99a08-7dd4-4c51-9a88-ada2a9c89feb eventCount=1
2025-11-09 14:30:06,028 DEBUG [org.keycloak.protocol.ssf.event.listener.DefaultSsfEventListener] (executor-thread-1) Security event received. eventId=YTBhYmRjMjktZTEyZC00NmE3LWI4Y2YtOTIxYzJkOTJlMmZj eventType=https://schemas.openid.net/secevent/caep/event-type/session-revoked subjectId=EmailSubjectId{email='[email protected]'} eventClass=org.keycloak.protocol.ssf.event.types.caep.SessionRevoked
2025-11-09 14:30:06,050 DEBUG [org.keycloak.protocol.ssf.event.listener.DefaultSsfEventListener] (executor-thread-1) Removed 1 sessions for user. realm=ssf-poc userId=302a333e-aa2d-46c1-af5d-de22576cd036 for SessionRevoked event. reasonAdmin=null reasonUser=null

@thomasdarimont thomasdarimont force-pushed the issue/gh-43614-ssf-support-v1 branch 2 times, most recently from 098ac04 to 998edb6 Compare November 13, 2025 13:21
@thomasdarimont thomasdarimont force-pushed the issue/gh-43614-ssf-support-v1 branch 2 times, most recently from fa479a4 to 27de092 Compare November 24, 2025 11:51
@thomasdarimont thomasdarimont changed the title Initial support for Shared Signals Framework with Push Delivery Support SSF Receivers with Push Delivery Nov 27, 2025
@thomasdarimont thomasdarimont force-pushed the issue/gh-43614-ssf-support-v1 branch 5 times, most recently from 4c289f8 to fd5db12 Compare December 3, 2025 09:59
- Add new experimental SSF feature flag
- Add SET parsing infrastructure
- Add support for Subject Identifier parsing
- Add receiver management
- Add transmitter stream / keys management
- Add support for SET PUSH Delivery

Fixes keycloak#43614

Signed-off-by: Thomas Darimont <[email protected]>
Signed-off-by: Thomas Darimont <[email protected]>
- Represent SSF Receivers as Identity Providers in Admin UI
- Gradually move from SsfReceiverModel to SsfReceiverProviderConfig
- Move to external stream management model (streams are created outside of Keycloak)
- Move verification functionality to SsfReceiverProvider
- Make SsfReceiverManager obsolete

Signed-off-by: Thomas Darimont <[email protected]>

# Conflicts:
#	js/apps/admin-ui/src/identity-providers/add/DetailSettings.tsx
#	services/src/main/resources/META-INF/services/org.keycloak.broker.provider.IdentityProviderFactory
- Represent SSF Receivers as Identity Providers in Admin UI
- Gradually move from SsfReceiverModel to SsfReceiverProviderConfig
- Move to external stream management model (streams are created outside of Keycloak)
- Move verification functionality to SsfReceiverProvider
- Make SsfReceiverManager obsolete

Signed-off-by: Thomas Darimont <[email protected]>
Signed-off-by: Thomas Darimont <[email protected]>
Signed-off-by: Thomas Darimont <[email protected]>
Signed-off-by: Thomas Darimont <[email protected]>
- Removed SCIM Events  (which are still in draft status https://www.ietf.org/archive/id/draft-ietf-scim-events-16.html)
- Revised JSON deserialization of SSF events (result is now SsfEvent instead of Map<String,Object>)
- Introduced StreamEvent base class for SSF Stream events
- Remove unnecessary methods

Signed-off-by: Thomas Darimont <[email protected]>
- Rename SsfSpi to SsfReceiverSpi
- Rename SsfReceiverProvider to SsfRegistrationProvider
- Rename SsfProvider to SsfReceiverProvider

This allows us to add SSF Transmitter support independently of the SSF Receiver support

Signed-off-by: Thomas Darimont <[email protected]>
@thomasdarimont thomasdarimont force-pushed the issue/gh-43614-ssf-support-v1 branch from fd5db12 to 9be27de Compare December 18, 2025 13:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add Support for SSF Receivers with Push Delivery

1 participant