Skip to main content

Webhook Notifications

Introduction

Welcome to the tutorial on webhook notifications in the Cloud Agent. In this tutorial, we will explore how webhook notifications can enhance your experience with the Cloud Agent by providing real-time updates on events. By leveraging webhook notifications, you can stay informed about important changes happening within the agent.

Understanding Webhook Notifications

What are Webhooks?

Webhooks enable real-time communication between applications by sending HTTP requests containing event data to specified endpoints (webhook URLs) when events occur. They establish a direct communication channel, allowing applications to receive instant updates and respond in a timely manner, promoting efficient integration between event-driven systems.

Purpose of Webhook Notifications in the Cloud Agent

Webhook notifications in the CLoud Agent serve as a vital feature, enabling you to receive timely updates on various events occurring within the agent. Webhooks allow you to receive HTTP requests containing event details at a specified endpoint (webhook URL). These events are specifically related to the execution of the Connect, Issue, and Presentation flows. Webhook notifications will be sent each time there is a state change during the execution of these protocols.

By leveraging webhooks, you can integrate the Cloud Agent seamlessly into your applications and systems. You can track and monitor the progress of the main flows, receiving timely updates about changes and events.

Configuring the Webhook Feature

Enabling the Webhook Feature

There are two kinds of webhook notifications: global webhooks and wallet webhooks. Global webhooks capture all events that happen on the Cloud Agent across all wallets, whereas wallet webhooks only capture events that are specific to assets within a particular wallet.

Enable global webhook using environment variables

The Cloud Agent uses the following environment variables to manage global webhook notifications:

NameDescriptionDefault
GLOBAL_WEBHOOK_URLThe webhook endpoint URL where the notifications will be sentnull
GLOBAL_WEBHOOK_API_KEYThe optional API key (bearer token) to use as the Authorization headernull

Enable wallet webhook for default wallet using environment variables

In a multi-tenant scenario, the Cloud Agent can optionally create a default wallet to simplify the development and deployment process. The webhook configuration for this default wallet can be defined using environment variables. After the default wallet is created, its webhook settings are stored in the system and are no longer influenced by these environment variables.

NameDescriptionDefault
DEFAULT_WALLET_ENABLEDAutomatically create default on the Cloud Agent startuptrue
DEFAULT_WALLET_WEBHOOK_URLThe webhook endpoint URL where the notifications will be sentnull
DEFAULT_WALLET_WEBHOOK_API_KEYThe optional API key (bearer token) to use as the Authorization headernull

Enable wallet hook using REST API

In a multi-tenant scenario, there is an option to configure wallet webhook parameters using a REST API, which offers more flexibility. For each individual wallet, users can create a new webhook by making a POST request to /events/webhooks, which in turn creates a new webhook resource specific to their wallet.

curl --location --request POST 'http://localhost:8080/cloud-agent/events/webhooks' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header "apiKey: $API_KEY" \
--data-raw '{
"url": "http://localhost:9095"
}'

Response Example:

{
"id": "e9569dd0-bffa-4be4-94fe-f5025a79029a",
"url": "http://localhost:9095",
"customHeaders": {},
"createdAt": "2023-09-12T08:39:03.871339Z"
}

Securing the Webhook Endpoint

It is essential to secure the webhook endpoint to protect the integrity and confidentiality of the event data. Consider the following best practices when securing your webhook endpoint:

  • Use HTTPS to encrypt communication between the Cloud Agent and the webhook endpoint.
  • Implement authentication mechanisms (e.g., API keys, tokens) to verify the authenticity of incoming requests.
  • Validate and sanitize incoming webhook requests to mitigate potential security risks.

One of the authorization mechanism for the Cloud Agent's webhook notifications is the bearer token. If configured, the token will be included in the Authorization header of the HTTP request sent by the agent to the webhook endpoint. You can configure this bearer token by setting the value of the GLOBAL_WEBHOOK_API_KEY or DEFAULT_WALLET_WEBHOOK_API_KEY environment variable.

An alternative approach is to make use of the customHeaders property within the REST API for configuring webhooks. This option offers increased flexibility when custom or multiple headers are needed.

Event Format and Types

Event Format

Webhook notifications from the Cloud Agent are sent as JSON payloads in the HTTP requests.

The event format is consistent across all events. Each event follows a common structure, while the 'data' field within the event payload contains information specific to the type of event. Here is an example of the JSON payload format:

{
"id": "cb8d4e96-30f0-4892-863f-44d49d634211",
"ts": "2023-07-06T12:01:19.769427Z",
"type": "xxxx",
"data": {
// Event-specific data goes here
},
"walletId": "00000000-0000-0000-0000-000000000000"
}

This event format ensures consistency and allows you to handle webhook notifications uniformly while easily extracting the relevant data specific to each event type from the data field.

Here is a complete example of a webhook notification event related to a connection flow state change (invitation generated):

{
"id": "cb8d4e96-30f0-4892-863f-44d49d634211",
"ts": "2023-07-06T12:01:19.769427Z",
"type": "ConnectionUpdated",
"data": {
"connectionId": "c10787cf-99bb-47f4-99bb-1fdcca32b673",
"label": "Connect with Alice",
"role": "Inviter",
"state": "InvitationGenerated",
"invitation": {
"id": "c10787cf-99bb-47f4-99bb-1fdcca32b673",
"type": "https://didcomm.org/out-of-band/2.0/invitation",
"from": "did:peer:2.Ez6LS...jIiXX0",
"invitationUrl": "https://my.domain.com/path?_oob=eyJpZCI6...bXX19"
},
"createdAt": "2023-07-06T12:01:19.760126Z",
"self": "c10787cf-99bb-47f4-99bb-1fdcca32b673",
"kind": "Connection"
},
"walletId": "00000000-0000-0000-0000-000000000000"
}

Common Event Types

The Cloud Agent sends webhook notifications for events related to protocol state changes in the Connect, Issue, Presentation flows, and also DID publication state changes. These events allow you to track the progress and updates within these flows in real-time.

The id field of the common event structure is the unique identifier (UUID) of the event and is randomly generated at event creation time.

The ts field contains the timestamp (date + time) at which the event was created.

The walletId field contains information about the wallet from which the event originates.

The type field indicates to which flow/process the received event is related, and hence the type of JSON payload that can be expected in the inner data field. Possible values are:

ValueDescription
ConnectionUpdatedAn update in the connection flow state
IssueCredentialRecordUpdatedAn update in the VC issuance flow state
PresentationUpdatedAn update in the VC presentation flow state
DIDStatusUpdatedAn update in the DID publication state

State change notifications that you can expect to receive through webhook notifications include:

  • Connection State Change: Notifies about state changes in the connection flow, such as InvitationGenerated, ConnectionRequestSent, ConnectionResponseReceived, etc. Please refer to the state field of the connection resource for an exhaustive list of states.
  • Credential State Change: Indicates changes in the credential issuance flow, such as OfferSent, RequestReceived, CredentialSent, etc. Please refer to the protocolState field of the credential resource for an exhaustive list of states.
  • Presentation State Change: Notifies about changes in the presentation flow, such as RequestReceived, PresentationGenerated, PresentationVerified, etc. Please refer to the status field of the presentation resource for an exhaustive list of states.
  • DID State Change: Notifies about DID-related state changes. Currently, only the Published DID publication state event will be notified.

Processing Webhook Notifications

Handling Incoming Webhook Requests

To handle incoming webhook notifications from the Cloud Agent in your application, follow these general steps:

  1. Receive the HTTP request at your specified webhook endpoint.
  2. Parse the JSON payload of the request to extract the event details.
  3. Process the event data according to your application's requirements.
  4. Send a response back to acknowledge the successful receipt of the webhook notification. For a successful reception, the response status code should be >= 200 and < 300. Any other response status code will lead to a new attempt from the Cloud Agent.

Error Handling and Retry Mechanisms

When working with webhook notifications in the Cloud Agent, it is important to consider error handling and retry mechanisms. In case of failed webhook notifications or errors, the Cloud Agent employs an automatic retry mechanism to ensure delivery. The agent will attempt to send the webhook notification up to three times, with a five-second interval between each attempt. Please note that the number of retries and the interval duration are currently not configurable in the Cloud Agent.

By default, this retry mechanism provides a reasonable level of reliability for delivering webhook notifications, allowing for temporary network issues or intermittent failures.

A basic Webhook implementation for logging requests

In the following example, we will demonstrate a simple Python code snippet that sets up a webhook endpoint and logs incoming HTTP requests to the console. This basic implementation can serve as a starting point for building more advanced webhook systems.

In the provided Python code snippet, the port on which the webhook listener will listen for incoming requests should be passed as a command-line parameter. This allows flexibility in starting multiple webhooks in parallel, which is useful when testing multiple locally running agents, e.g. for a holder, an issuer, and/or a verifier.

#!/usr/bin/env python3
"""
Very simple HTTP server in python for logging requests
Usage::
./server.py [<port>]
"""
import logging
import json
from http.server import BaseHTTPRequestHandler, HTTPServer

grey = "\x1b[38;20m"
yellow = "\x1b[33;20m"
green = "\x1b[32;20m"
red = "\x1b[31;20m"
bold_red = "\x1b[31;1m"
reset = "\x1b[0m"

consoleHandler = logging.StreamHandler()
formatter = logging.Formatter(f"""%(asctime)s - %(levelname)s - %(name)s
--------------------------------------- request ---------------------------------------
{green}%(method)s %(path)s{reset}
%(headers)s
{yellow}%(data)s{reset}
-----------------------------------
"""
)
consoleHandler.setFormatter(formatter)
consoleHandler.setLevel(logging.INFO)

logger = logging.getLogger('http-request')
logger.setLevel(logging.INFO)
logger.addHandler(consoleHandler)

class S(BaseHTTPRequestHandler):

def _set_response(self):
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.end_headers()

def do_GET(self):
logging.info("GET request,\nPath: %s\nHeaders:\n%s\n", str(self.path), str(self.headers))
self._set_response()
self.wfile.write("GET request for {}".format(self.path).encode('utf-8'))

def do_POST(self):
content_length = int(self.headers['Content-Length']) # <--- Gets the size of data
post_data = self.rfile.read(content_length) # <--- Gets the data itself
json_obj = json.loads(post_data.decode('utf-8'))
json_data = json.dumps(json_obj, indent=2)
logger.info(msg="Request content", extra={
'method': "POST",
'path': str(self.path),
'headers': str(self.headers),
'data': json_data
})
self._set_response()
self.wfile.write("POST request for {}".format(self.path).encode('utf-8'))

def log_message(self, format, *args):
pass


def run(server_class=HTTPServer, handler_class=S, port=80):
server_address = ('', port)
httpd = server_class(server_address, handler_class)
try:
httpd.serve_forever()
except KeyboardInterrupt:
pass
httpd.server_close()


if __name__ == '__main__':
from sys import argv

if len(argv) == 2:
run(port=int(argv[1]))
else:
run()

Conclusion

Congratulations! You've learned about webhook notifications in the Cloud Agent. By leveraging this feature, you can receive real-time updates on events happening within the agent, enabling you to integrate the Cloud Agent seamlessly into your applications. Remember to secure your webhook endpoint and handle webhook notifications effectively to maximize the benefits of this feature.

Start integrating webhook notifications into your Cloud Agent workflow and unlock the power of real-time event updates!

If you have any further questions or need assistance, don't hesitate to reach out to the Identus support team or refer to the official documentation for more details.