Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Shared Signals Framework 仕様解説

Shared Signals Framework 仕様解説

2026/11/09 開催
OpenID TechNight vol.24 ~ SSF × AIdentity 発表資料

Shared Signals Framework 仕様解説

株式会社Authlete
川﨑 貴彦

Avatar for OpenID Foundation Japan

OpenID Foundation Japan

November 09, 2026

More Decks by OpenID Foundation Japan

Other Decks in Technology

Transcript

  1. Speaker Co-founder of Authlete, Inc. Software Engineer. After graduating from

    Keio University’s Faculty of Policy Management in 1997, he worked at four private companies before becoming independent in 2009. He has been involved in network and database systems, Java Virtual Machine, mobile applications, and distributed systems. Takahiko Kawasaki He devised a unique architecture that modularizes and provides OAuth 2.0 / OpenID Connect implementations as SaaS — global standard technologies for Web API security and Identity Federation. In 2015, he founded Authlete, Inc. Currently, he participates in global standardization efforts and translates them into commercial implementations. Tech blog in English: https://darutk.medium.com Tech blog in Japanese: https://qiita.com/TakahikoKawasaki
  2. SSF Defines Transmitter's Behavior { Transmitter : 1. generates Security

    Event Tokens (SETs) 2. delivers SETs to receivers Receiver "alg": "ES256", "typ": "secevent+jwt" } { "iss": "https://idp.example.com/", "jti": "756E69717565206964656E746966696572", "iat": 1520364019, "txn": "8675309", "aud": "636C69656E745F6964", "sub_id": { Subject Identifier "format": "phone_number", "phone_number": "+1 206 555 0123" }, Transmitter delivers Security Event Token generates SET "events": { "https://schemas.openid.net/secevent/risc /event-type/account-disabled": { "reason": "hijacking" } Event Type URI & Payload } } OpenID Shared Signals Framework Specification 1.0 Figure 9: Example: SET Containing a RISC Event with a Phone Number Subject
  3. Receiver's Viewpoint Receiver : 1. requests the Transmitter to create

    a stream • delivery method (POLL or PUSH) • event type URIs 2. specifies which subjects' events to be delivered • specified subjects only, or • all with specified subjects excluded 3. receives Security Event Tokens Stream • Event Delivery Method • Events to Watch • Subjects to Watch
  4. Transmitter's Endpoints Event Sources Transmitter Transmitter's metadata /.well-known/ssf-configuration Transmitter's JWK

    Set JWK Set Document Endpoint Stream management Configuration Endpoint Event Registration queue DELETE GET PATCH POST PUT Stream status management Status Endpoint GET POST Subjects to watch Add Subject Endpoint Remove Subject Endpoint Stream connectivity check Verification Endpoint Poll-based event delivery Polling Endpoint Push-based event delivery Event Queues queue deliver deliver
  5. Stream Create Request (for Push-Based Delivery) POST /ssf/configuration HTTP/1.1 Host:

    transmitter.example.com Content-Type: application/json Authorization: Bearer Access Token { Stream Create Request (PUSH) urn:ietf:rfc:8935 represents the Push-Based Delivery Method "delivery": { Event Delivery Settings "method": "urn:ietf:rfc:8935", "endpoint_url": "https://receiver.example.com/events", "authorization_header": "Basic dHJhbnNtaXR0ZXI6cGFzc3dvcmQ=" }, "events_requested": [ Events to Watch "https://schemas.openid.net/secevent/risc/ event-type/credential-compromise" ] }
  6. Stream Create Request (for Poll-Based Delivery) POST /ssf/configuration HTTP/1.1 Host:

    transmitter.example.com Content-Type: application/json Authorization: Bearer Access Token { Stream Create Request (POLL) urn:ietf:rfc:8936 represents the Poll-Based Delivery Method "delivery": { "method": "urn:ietf:rfc:8936" }, "events_requested": [ "https://schemas.openid.net/secevent/risc/ event-type/credential-compromise" ] Event Delivery Settings Events to Watch } NOTE: When the delivery method is POLL, the entire delivery object can be omitted because POLL is the default method.
  7. Stream Create Response HTTP/1.1 201 Created Content-Type: application/json Stream Create

    Response { "stream_id": "stj3odpcfg19u6q62t2h7k0uk3t7srkdai6e0ccd7jd4ognt", "iss": "https://transmitter.example.com", "aud": "ssf-receiver", The stream ID assigned to the new stream "events_supported": [ "https://schemas.openid.net/secevent/risc/event-type/credential-compromise", "https://schemas.openid.net/secevent/risc/event-type/session-revoked" ], "events_requested": [ "https://schemas.openid.net/secevent/risc/event-type/credential-compromise" ], supported events "events_delivered": [ "https://schemas.openid.net/secevent/risc/event-type/credential-compromise" ∧ requested events ], delivered events "delivery": { "method": "urn:ietf:rfc:8936", "endpoint_url": "https://transmitter.example.com/ssf/poll/stj3odpcfg19u6q62t2h7k0uk3t7srkdai6e0ccd7jd4ognt" } } When the delivery method is POLL, the server-side polling endpoint is specified by the endpoint_url property.
  8. Subjects to Watch / Initial State 1. NONE – no

    subjects are watched The receiver needs to add subjects to the stream's watch list by calling the transmitter's Add Subject Endpoint. 2. ALL – all subjects are watched The receiver may remove subjects from the stream's watch list by calling the transmitter's Remove Subject Endpoint. The initial state is indicated by the default_subjects property in the transmitter's metadata. "default_subjects": "NONE" or "default_subjects": "ALL"
  9. Subjects to Watch / Issue 326 – default_subjects per stream

    TakahikoKawasaki opened Apr 8 https://github.com/openid/sharedsignals/issues/326 Depending on whether the transmitter’s default_subjects is set to NONE or ALL, one of the following two use cases becomes impractical in terms of stream creation and configuration: 1. Receiving events for all subjects 2. Receiving events only for specific subjects If default_subjects is NONE, it is impractical to call the add_subject_endpoint once for every subject in order to receive events for all subjects. Conversely, if default_subjects is ALL, it is impractical to call the remove_subject_endpoint once for every other subject in order to receive events only for specific subjects. I believe this issue can be resolved if there is a way to configure default_subjects on a per-stream basis when creating a stream. For example, this could be achieved by adding a default_subjects property to the Stream Configuration (i.e., allowing each stream to have its own default_subjects setting). If one wants to receive events for all subjects, this can be achieved by creating a stream with default_subjects=ALL. On the other hand, if one wants to receive events only for specific subjects, this can be achieved by creating a stream with default_subjects=NONE and then calling the add_subject_endpoint. As a concrete proposal, I'd like to suggest adding a default_subjects property to the Stream Configuration as described below. What do you think? default_subjects Receiver-Supplied, OPTIONAL. The value MUST be either "ALL" or "NONE". If omitted when creating the stream, the transmitter's default_subjects configuration is inherited. "ALL" indicates that events for all subjects are delivered to the stream, and the Receiver must call the remove_subject_endpoint to stop receiving events for specific subjects. Conversely, "NONE" indicates that events are not delivered to the stream by default (except in special cases such as verification events), and the Receiver must call the add_subject_endpoint to receive events for specific subjects.
  10. Add Subject Request POST /ssf/add_subject HTTP/1.1 Host: transmitter.example.com Content-Type: application/json

    Authorization: Bearer Access Token Add Subject Request { "stream_id": "stj3odpcfg19u6q62t2h7k0uk3t7srkdai6e0ccd7jd4ognt", Subject to Add "subject": { "format": "email", "email": "[email protected]" } }
  11. Remove Subject Request POST /ssf/remove_subject HTTP/1.1 Host: transmitter.example.com Content-Type: application/json

    Authorization: Bearer Access Token Remove Subject Request { "stream_id": "stj3odpcfg19u6q62t2h7k0uk3t7srkdai6e0ccd7jd4ognt", Subject to Remove "subject": { "format": "email", "email": "[email protected]" } }
  12. Poll Request POST /ssf/poll/{stream_id} HTTP/1.1 Host: transmitter.example.com Content-Type: application/json Authorization:

    Bearer Access Token Poll Request { "maxEvents": 5, "returnImmediately": false } • maxEvents – OPTIONAL. The maximum number of Security Event Tokens to return. • returnImmediately – OPTIONAL. Whether to return immediately even if no events are available. false (default) indicates long polling (RFC 6202).
  13. Poll Response Poll Response HTTP/1.1 200 OK Content-Type: application/json The

    value of the jti claim of the security event token { "sets": { "evrum9ggbpnjc49on42t5v892c74uiq4ujoe9f10amtbujtg": "eyJraWQiOiJCcmpYY3h3MDlka3BQR0lKdG55WDY3VTROOHg1aGc1bzVTSzFvT29yMFJjIiwidHlwIjoi c2VjZXZlbnQrand0IiwiYWxnIjoiRVMyNTYifQ.eyJpc3MiOiJodHRwczovL3RyYW5zbWl0dGVyLmV4Y W1wbGUuY29tIiwiYXVkIjoic3NmLXJlY2VpdmVyIiwianRpIjoiZXZydW05Z2dicG5qYzQ5b240MnQ1d jg5MmM3NHVpcTR1am9lOWYxMGFtdGJ1anRnIiwiaWF0IjoxNzczMDYyNDMzLCJ0eG4iOiJhdHVvZm1kb GxkdmwwMW9mZGowb3F0a3NzNzFydWkycXZwODBrMGQ5NHR2czNyOTgiLCJ0b2UiOjE3NzMwNjI0MjYsI nN1Yl9pZCI6eyJmb3JtYXQiOiJvcGFxdWUiLCJpZCI6InN0ajNvZHBjZmcxOXU2cTYydDJoN2swdWszd DdzcmtkYWk2ZTBjY2Q3amQ0b2dudCJ9LCJldmVudHMiOnsiaHR0cHM6Ly9zY2hlbWFzLm9wZW5pZC5uZ XQvc2VjZXZlbnQvc3NmL2V2ZW50LXR5cGUvdmVyaWZpY2F0aW9uIjp7InN0YXRlIjoiRmpwU0s5cVZUR iJ9fX0.t_DTAQ0ziqz8YtfjhOfSW5Bl4YHkCa782Bd8uuwbRu2OL8AGPLAKVhe0Z3tq4HKkMl8NSzGL9 dMAu2Izi-O2Rw" }, "moreAvailable": false } Whether more events are available The security event token
  14. Poll Request with Ack POST /ssf/poll/{stream_id} HTTP/1.1 Host: transmitter.example.com Content-Type:

    application/json Authorization: Bearer Access Token Poll Request with Ack { "ack": [ "evrum9ggbpnjc49on42t5v892c74uiq4ujoe9f10amtbujtg" ] }
  15. Push Request (from Transmitter to Receiver) POST /ssf/push/{stream_id} HTTP/1.1 Host:

    receiver.example.com Content-Type: application/secevent+jwt Authorization: Basic dHJhbnNtaXR0ZXI6cGFzc3dvcmQ= Push Request eyJraWQiOiJCcmpYY3h3MDlka3BQR0lKdG55WDY3VTROOHg1aGc1bzVTSzFvT29yMFJjIiwidH lwIjoic2VjZXZlbnQrand0IiwiYWxnIjoiRVMyNTYifQ.eyJpc3MiOiJodHRwczovL3RyYW5zb Wl0dGVyLmV4YW1wbGUuY29tIiwiYXVkIjoic3NmLXJlY2VpdmVyIiwianRpIjoiZXZydW05Z2d icG5qYzQ5b240MnQ1djg5MmM3NHVpcTR1am9lOWYxMGFtdGJ1anRnIiwiaWF0IjoxNzczMDYyN DMzLCJ0eG4iOiJhdHVvZm1kbGxkdmwwMW9mZGowb3F0a3NzNzFydWkycXZwODBrMGQ5NHR2czN yOTgiLCJ0b2UiOjE3NzMwNjI0MjYsInN1Yl9pZCI6eyJmb3JtYXQiOiJvcGFxdWUiLCJpZCI6I nN0ajNvZHBjZmcxOXU2cTYydDJoN2swdWszdDdzcmtkYWk2ZTBjY2Q3amQ0b2dudCJ9LCJldmV udHMiOnsiaHR0cHM6Ly9zY2hlbWFzLm9wZW5pZC5uZXQvc2VjZXZlbnQvc3NmL2V2ZW50LXR5c GUvdmVyaWZpY2F0aW9uIjp7InN0YXRlIjoiRmpwU0s5cVZURiJ9fX0.t_DTAQ0ziqz8YtfjhOf SW5Bl4YHkCa782Bd8uuwbRu2OL8AGPLAKVhe0Z3tq4HKkMl8NSzGL9dMAu2Izi-O2Rw NOTE: If the delivery.authorization_header property is specified in the stream configuration, push requests include an Authorization header with that value.
  16. Push Request with Multiple SETs POST /ssf/push/{stream_id} HTTP/1.1 Push Request

    with Multiple SETs Host: receiver.example.com Content-Type: application/secevents+json Authorization: Basic dHJhbnNtaXR0ZXI6cGFzc3dvcmQ= { "sets": { "4d3559ec67504aaba65d40b0363faad8": "eyJ......", "3d0c3cf797584bd193bd0fb1bd4e7d30": "eyJ......" } } [Individual Draft] Push-Based Delivery For Multiple Security Event Tokens (SET) Using HTTP https://datatracker.ietf.org/doc/draft-deshpande-secevent-http-multi-set-push/
  17. Verification Request POST /ssf/verification HTTP/1.1 Host: transmitter.example.com Content-Type: application/json Authorization:

    Bearer Access Token Verification Request { "stream_id": "stj3odpcfg19u6q62t2h7k0uk3t7srkdai6e0ccd7jd4ognt", "state": "FjpSK9qVTF" } • stream_id – REQUIRED. The stream ID. • state – OPTIONAL. An arbitrary string embedded in the payload of the security event token corresponding to the verification request.
  18. Verification Event Payload { Verification Event Payload "iss": "https://transmitter.example.com", "aud":

    "ssf-receiver", "jti": "evrum9ggbpnjc49on42t5v892c74uiq4ujoe9f10amtbujtg", "iat": 1773062433, "txn": "atuofmdlldvl01ofdj0oqtkss71rui2qvp80k0d94tvs3r98", "toe": 1773062426, "sub_id": { The stream ID "format": "opaque", "id": "stj3odpcfg19u6q62t2h7k0uk3t7srkdai6e0ccd7jd4ognt" }, The event type URI of verification event "events": { "https://schemas.openid.net/secevent/ssf/event-type/verification": { "state": "FjpSK9qVTF" } The state value specified in the verification request } }
  19. Stream Creation curl ${CONFIGURATION_ENDPOINT} \ --oauth2-bearer ${ACCESS_TOKEN} \ --json '{

    "events_requested": [ "https://schemas.openid.net/secevent/risc/event-type/credential-compromise" ] }' Verification Request curl –i ${VERIFICATION_ENDPOINT} \ --oauth2-bearer ${ACCESS_TOKEN} \ --json '{ "stream_id": "'${STREAM_ID}'" }'
  20. Polling curl ${POLL_ENDPOINT} \ --oauth2-bearer ${ACCESS_TOKEN} \ --json '{}' Subject

    Addition curl -i ${ADD_SUBJECT_ENDPOINT} \ --oauth2-bearer ${ACCESS_TOKEN} \ --json '{ "stream_id": "'${STREAM_ID}'", "subject": { "format": "email", "email": "[email protected]" } }'
  21. Event Registration (Implementation-Dependent) curl ${EVENT_REGISTRATION_API}?pretty=true \ --oauth2-bearer ${BACKEND_ACCESS_TOKEN} \ --json

    '{ "sub_id": { "format": "email", "email": "[email protected]" }, "events": { "https://schemas.openid.net/secevent/risc/event-type/credential-compromise":{ "credential_type": "password" } } }'