Concepts#

TeaL binds and distributes events received by listeners through dispatchers to clients, such as Teacups or Woob.

The following sections describe these concepts in depth.

Events#

An event in this context is an action from another actor that is registered through TeaL.

The following subsections describe the events supported by TeaL.

Callback events#

Callbacks events are events where specific HTTP endpoints are called with a GET method, and a state opaque parameter. This state must be unique depending on the context of the redirect flow.

Callback events must be bound by state first, with the following configuration:

  • An expiration date and time for the state, after which events are no longer emitted for said state.

  • An optional final redirect URL, to which to redirect the end user before sending the event.

  • Whether to read the fragment for a given state, or not.

This configuration is stored in Redis (see Redis usage), and indexed by state.

Note

Some APIs and authentication flows redirect to the callback with parameters sent in the fragment[1] rather than the query string, such as:

https://example.org/callback?state=123#code=456

This is usually because such APIs expect the callback to be processed by a Javascript application within the browser directly, instead of a backend application.

For offering compatibility with such an approach, if the option to forcefully get a fragment is active for a given state, the end user will be presented with a simple HTML document with some Javascript gathering the fragment, then sending it to the backend before optionally redirecting the end user.

Note

Some APIs and authentication flows redirect with an alternative query separator to ?, such as:

https://example.org/callback&state=123&code=abc

For offering compatibility with such an approach, if the standard query separator is not found and an alternative separator such as & is present, it is used as such.

Note that for easier management of such border cases, the alternative query separator is replaced by the standard one before the URL is sent on the message queues; this means that, for the above URL, the following callback message is sent on the message queues:

{
    "url": "https://example.org/callback?state=123&code=abc",
    "state": "123"
}

These events contain the following data:

  • The state for which the event was raised.

  • The full URL, optionally including a fragment.

Note that if the callback is received multiple times, this will happen every time, so clients may receive multiple callback events for the same callback state.

Freestanding callback states#

In order for the TeaL Web Listener to be used in some more applications, a fallback to stored callback states can be freestanding states, i.e. states that carry final redirect information on their own. Such states don’t need to be bound, and will systematically raise callback events.

The only currently implemented fallback with such states are Powens-style freestanding callback states, for which support can be enabled on the TeaL Web Listener’s POWENS_REDIRECT_FALLBACK configuration variable.

The two allowed formats are the following, in order of evaluation:

Note that these are only tried if there is no stored callback state information for the given state. See the class definitions for more information.

OpenID Connect CIBA callback events#

Callback events for the ping and push modes of OpenID Connect Client-Initiated Backchannel Authentication Flow are supported as events you can subscribe to.

Currently, such events are bound by authentication request identifier, considered globally unique at a given moment. They can be of three kinds:

  1. A simple ping callback, only including the authentication request identifier and the client notification token provided as a Bearer token, as defined in section 10.2.

  2. A successful token delivery callback, including all of the above plus the obtained token data, as defined in section 10.3.1.

  3. A push error callback, including the authentication request identifier, the client notification token provided as a Bearer token, and the error code and optional description, as defined in section 12.

These events are represented on message queues as a single message representation with the following optional components:

  • A “push token” component describing the obtained token, only present in the second case.

  • A “push error” component describing the obtained error, only present in the third case.

Powens webhook events#

Powens webhooks are also events you can subscribe to.

Currently, they can only be registered for an entire Powens domain, e.g. receive all Powens webhooks for domain budgea.biapi.pro.

Listeners#

flowchart LR end_user["End User"] other_actors["Other actors"] listener["TeaL Listener"] mq["RabbitMQ"] redis["Redis"] end_user & other_actors -->|Call| listener listener -->|Emit| mq listener -->|"Read Callbacks"| redis

Listeners in TeaL are components that listen to events and, if such events are considered legitimate, pushes them onto the message queues, and may have side effects depending on stored data in Redis.

TeaL Web listener#

This listener is defined in teal.web_listener. It implements listening to web related events, including Callback events and Powens webhook events.

Callback endpoints using the TeaL Web listener#

Callback events are listened for on three endpoints:

  • /callback: simple callbacks.

  • /errback: simple callbacks for errors.

  • /raw-callback: callback with a raw URL, for use with fragment reading.

If /callback or /errback don’t find a state in the provided query parameters, they will try to redirect to /raw-callback using Javascript to try and obtain a state from the fragment if present.

If /callback or /errback find a state that is valid and not expired, and the fragment is required to be gathered, they will try to redirect to /raw-callback using Javascript to try and obtain it.

For all of these endpoints, if a state has been found, and if the provided state is invalid or expired, an HTTP 404 response will be provided with the text Missing state.

OpenID Connect CIBA callback endpoints using the TeaL Web Listener#

Callback events in the context of OpenID Connect Client-Initiated Backchannel Authentication with ping / push events are listened to on the following endpoint:

POST /openid-ciba-callback

Powens webhook endpoints using the TeaL Web listener#

Powens webhook events are listened for on the following endpoint:

POST /powens-webhook/{domain}/{event}

This route must be configured manually for every webhook in the Powens console, with required authentication (either HMAC or user token).

Dispatchers#

flowchart LR mq["RabbitMQ"] redis["Redis"] dispatcher["TeaL Dispatchers"] clients["Clients (teacups, ...)"] clients -->|Register| dispatcher dispatcher -->|Emit| clients dispatcher -->|Bind| mq mq -->|Emit| dispatcher dispatcher --> |"Create, Expire & Read Callbacks"| redis

Dispatchers in TeaL are components that listen to events from the message queues, and redistribute them to remote clients or systems.

TeaL Websocket Dispatcher#

This dispatcher is defined in teal.websocket_dispatcher. It allows opening websockets and, through said websockets, registering to events and creating data on Redis. Events are sent as push messages onto the websocket.

Dispatcher metadata#

The dispatcher provides useful metadata for clients to use with the client/dispatcher pub/sub protocol through the /.well-known/teapots-teal-metadata endpoint:

  • server_version: The version of the server, if exposed.

  • websocket_url: The fully qualified HTTP URL for connecting to the websocket.

  • callback_url: The fully qualified HTTP callback URL to use, in conjunction with the registered state.

  • errback_url: The fully qualified HTTP callback URL to use for errors, in conjunction with the registered state.

  • openid_ciba_callback_url: The fully qualified HTTP callback URL to use for OpenID Client-Initiated Backchannel Authentication (CIBA) ping and push flows.

Note

An example output for this endpoint is the following:

{
    "server_version": "0.2",
    "websocket_url": "ws://localhost:8081/websocket",
    "callback_url": "http://localhost:8080/callback",
    "errback_url": "http://localhost:8080/errback",
    "openid_ciba_callback_url": "http://localhost:8080/openid-ciba-callback"
}

Websocket protocol#

For creating stored states, and binding and receiving events, the Websocket Dispatcher implements a specific protocol; see Websocket Client/Dispatcher Protocol for more information.