Navigation

Configure Service Webhooks

On this page

Overview

Some external services allow you to create incoming webhooks that external clients can call over HTTP. You can create webhooks for these services from the Realm UI or by importing a service configuration directory that contains a webhook configuration. Select the tab below that corresponds to the method you want to use.

Procedure

1

Set Up a New Webhook

Incoming webhooks are scoped to individual services. You can create and manage a webhook from its associated service page in the Realm UI.

To create an incoming webhook:

  1. Click Services in the left navigation menu.
  2. Click the Service for which you want to add an incoming webhook.
  3. Select the Incoming Webhooks tab for the service.
  4. Click Add Incoming Webhook. Realm will redirect you to the Settings screen for the new webhook.
2

Name the New Webhook

Enter a unique, identifying name for the webhook in the Webhook Name field. This name must be distinct from any other webhooks that you’ve created for the service.

3

Configure User Authentication

Functions in Realm, including webhooks, always execute in the context of a specific application user or as the system user, which bypasses rules. To configure the webhook’s execution user, specify the type of authentication that Realm should use for the webhook.

Authentication Type Description
Application Authentication

This type of authentication configures a webhook to run in the context of an existing application user specified by each incoming request. Incoming requests must include the user’s authentication provider credentials in either the request body or the request headers.

The following examples demonstrate the field names and values for each supported authentication provider:

{
  "email": "<User's Email Address>",
  "password": "<User's Password>"
}
{
  "api-key": "<User's API Key>"
}
{
  "jwtTokenString": "<User's JWT Token>"
}

Do Not Use Both Headers and Body Fields

If a request includes credentials in both the request headers and the request body, then Realm throws an error and does not execute the function.

System This type of authentication configures a webhook to run as the system user, which has full access to MongoDB CRUD and Aggregation APIs and is not affected by any rules, roles, or permissions.
User ID This type of authentication configures a webhook to always run as a specific application user.
Script This type of authentication configures a webhook to run as a specific application user determined by the result of a custom function that you define. The function must return a specific user’s id string or can specify a system user by returning { "runAsSystemUser": true }.
4

Select the Webhook’s HTTP Method

You can require that incoming requests use a specific HTTP method or you can accept all HTTP methods and handle each one individually in the webhook function by inspecting the httpMethod property on the context.request object, as in the following example function:

exports = function(payload, response) {
  switch(context.request.httpMethod) {
    case "GET": { /* Handle GET requests */ }
    case "POST": { /* Handle POST requests */ }
    case "PUT": { /* Handle PUT requests */ }
    case "DELETE": { /* Handle DELETE requests */ }
    case "PATCH": { /* Handle PATCH requests */ }
    default: {}
  }
}
The HTTP method dropdown input in the UI
5

Configure the Webhook Response

You can send a configurable HTTP Response to external services that call the webhook.

If you enable Respond With Result, the webhook will respond to incoming requests with a basic HTTP 200 response that includes the webhook function return value as its body field. You can configure a custom HTTP response from within the webhook function using the response object that Realm automatically passes as the second argument.

6

Specify an Authorization Expression

You can dynamically authorize requests based on the contents of each request by defining a Can Evaluate JSON expression. Realm evaluates the expression for every incoming request that the webhook receives. If you do not specify an expression then Realm automatically authorizes all authenticated incoming requests.

The expression can expand standard expression variables, including the %%request expansion.

7

Specify the Request Validation Method

To validate that a webhook request was sent from a trusted source, some external services require that incoming requests incorporate a secret string in one of several prescribed manners. Other services, like the HTTP service, allow you to optionally require request validation.

If your webhook requires request validation:

  1. Select the request validation method.
  2. Enter a Secret string to use in the request validation process.
8

Write the Webhook Function

Once you’ve configured the webhook, all that’s left is to write the function that executes when someone calls the webhook. Realm automatically passes two objects as the webhook function’s arguments:

Argument Description
payload An EJSON representation of the incoming request payload. The contents of the payload document will vary depending on the service and event that caused a webhook to fire. For a description of the payload object for a specific service, see that service’s reference page.
response An HTTP response object that configures Realm’s response to the client that called the webhook. The object has methods that allow you to set the response’s headers, body, and status code. Calling any of these methods overrides the default response behavior.

You can use the following webhook function as a base for your own webhook:

exports = async function(payload, response) {
  // Convert the webhook body from BSON to an EJSON object
  const body = EJSON.parse(payload.body.text());

  // Execute application logic, such as working with MongoDB
  if(body.someField) {
    const mdb = context.services.get('mongodb-atlas');
    const requests = mdb.db("demo").collection("requests")
    const { insertedId } = await requests.insertOne({ someField: body.someField });
    // Respond with an affirmative result
    response.setStatusCode(200)
    response.setBody(`Successfully saved "someField" with _id: ${insertedId}.`);
  } else {
    // Respond with a malformed request error
    response.setStatusCode(400)
    response.setBody(`Could not find "someField" in the webhook request body.`);
  }
  // This return value does nothing because we already modified the response object.
  // If you do not modify the response object and you enable *Respond with Result*,
  // Realm will include this return value as the response body.
  return { msg: "finished!" };
}

Note

If you want to debug a webhook function response from the function editor, you must manually provide the HTTP response object when you run the function.

exports(
  { body: "This document is the webhook payload" },
  new HTTPResponse()
)
9

Save the Webhook

You must save changes to your webhook before they take effect. To do so, click Save from either the Settings screen or the Function Editor.

1

Export Your Realm Application

To create new incoming webhook with realm-cli, you need a previously created application configuration.

You can export your application from the Import/Export App tab of the Deploy page in the Realm UI, or by running the following command from an authenticated instance of realm-cli:

realm-cli export --app-id=<App ID>
2

Add a Webhook Configuration Directory

Create a new subdirectory in the /<service>/incoming_webhooks folder of the application directory that you exported, where <service> is the service that you want to add a webhook to. The name of the subdirectory should match the configured name of the webhook.

mkdir -p services/<service>/incoming_webhooks/<webhook name>
3

Add a Webhook Configuration File

Add a file named config.json to the new webhook directory. The configuration file should have the following form:

{
  "name": "<Unique Webhook Name>",
  "respond_result": <boolean>,
  "run_as_authed_user": <boolean>,
  "run_as_user_id": "<Realm User ID>",
  "run_as_user_id_script_source": "<Stringified Function>",
  "can_evaluate": <JSON Expression>,
  "disable_arg_logs": <boolean>,
  "options": <document>,
}
4

Name the New Webhook

Enter a name for the webhook in the configuration file’s name field. This name must be distinct from any other webhooks that you’ve created for the service.

{
  "name": "<Unique Webhook Name>"
}
5

Configure User Authentication

Specify the type of authentication that Realm should use for the webhook. Realm supports the following webhook authentication methods:

Authentication Method Description
Application Authentication

This type of authentication configures a webhook to run in the context of an existing application user specified by each incoming request. Incoming requests must include the user’s authentication provider credentials in either the request body or the request headers.

To configure a webhook to use application authentication, set the value of run_as_authed_user to true:

{
  "run_as_authed_user": true,
  "run_as_user_id": "",
  "run_as_user_id_script_source": "",
}

Example

The following examples demonstrate the field names and values that incoming requests should include as body or header fields for each supported authentication provider:

{
  "email": "<User's Email Address>",
  "password": "<User's Password>"
}
{
  "api-key": "<User's API Key>"
}
{
  "jwtTokenString": "<User's JWT Token>"
}

Do Not Use Both Headers and Body Fields

If a request includes credentials in both the request headers and the request body, then Realm throws an error and does not execute the function.

System

This type of authentication configures a webhook to run as the system user, whichc has full access to MongoDB CRUD and Aggregation APIs and is not affected by any rules, roles, or permissions.

To configure a webhook to run as a system user, do not set any other authentication fields:

{
  "run_as_authed_user": false,
  "run_as_user_id": "",
  "run_as_user_id_script_source": "",
}
User ID

This type of authentication configures a webhook to always run as a specific application user.

To configure a webhook to always run as a specific user, set run_as_user_id to the user’s id:

{
  "run_as_authed_user": false,
  "run_as_user_id": "<Realm User ID>",
  "run_as_user_id_script_source": "",
}
Script

This type of authentication configures a webhook to run as a specific application user determined based on the result of a custom function that you define. The function must return a specific user’s id string or can specify a system user by returning { "runAsSystemUser": true}.

To configure a webhook to run as a user determined by a function, set run_as_user_id_script_source to the stringified function code:

{
  "run_as_authed_user": false,
  "run_as_user_id": "",
  "run_as_user_id_script_source": "<Stringified Function>",
}
6

Specify the Webhook’s HTTP Method

You can require that incoming requests use a specific HTTP method or you can accept all HTTP methods and handle each one individually in the webhook function by inspecting the httpMethod property on the context.request object, as in the following example function:

exports = function(payload, response) {
  switch(context.request.httpMethod) {
    case "GET": { /* Handle GET requests */ }
    case "POST": { /* Handle POST requests */ }
    case "PUT": { /* Handle PUT requests */ }
    case "DELETE": { /* Handle DELETE requests */ }
    case "PATCH": { /* Handle PATCH requests */ }
    default: {}
  }
}

To specify a webhook method, set the options.httpMethod field to the name of the method using all capital letters or "ANY".

{
  "options": {
    "httpMethod": "POST"
  }
}
7

Configure the Webhook Response

You can send a configurable HTTP Response to external services that call the webhook. To configure the webhook to send a response to incoming requests, set respond_result to true.

If you enable Respond With Result, the webhook will respond to incoming requests with a basic HTTP 200 response that includes the webhook function return value as its body field. You can configure a custom HTTP response from within the webhook function using the response object that Realm automatically passes as the second argument.

8

Specify an Authorization Expression

You can dynamically authorize requests based on the contents of each request by defining a Can Evaluate JSON expression. Realm evaluates the expression for every incoming request that the webhook receives. The expression can expand standard expression variables, including the %%request expansion.

To define an authorization expression, set the value of the can_evaluate field to the expression. If you do not specify an expression then Realm automatically authorizes all authenticated incoming requests.

Example

The following expression only authorizes incoming requests if the sender’s IP address is not included in the list of addresses.

{
    "%%request.remoteIPAddress": {
        "%nin": [
            "248.88.57.58",
            "19.241.23.116",
            "147.64.232.1"
        ]
    }
}
9

Specify the Request Validation Method

To validate that a webhook request was sent from a trusted source, some external services require that incoming requests incorporate a secret string in one of several prescribed manners. Other services, like the HTTP service, allow you to optionally require request validation.

You can configure a webhook’s request authorization method in the options document of the webhook configuration. Realm supports the following request validation methods:

Method Description
No Additional Authorization

Incoming webhook requests do not require additional authorization.

{
  "validationMethod": "NO_VALIDATION"
}
Verify Payload Signature

Incoming webhook requests must include a hashed signature of the request body and a secret value. For details, refer to Payload Signature Verification.

{
  "validationMethod": "VERIFY_PAYLOAD",
  "secret": "<Secret Value>"
}
Require Secret

Incoming webhook requests must include a secret string value as the secret query parameter in the webhook URL. For details, refer to Secret as a Query Parameter.

{
  "validationMethod": "SECRET_AS_QUERY_PARAM",
  "secret": "<Secret Value>"
}
10

Add the Webhook Function Source Code

Add a file named source.js to the new webhook directory. The file should contain a valid function that will execute when the webhook is called.

Realm automatically passes two objects as the webhook function’s arguments:

Argument Description
payload An EJSON representation of the incoming request payload. The contents of the payload document will vary depending on the service and event that caused a webhook to fire. For a description of the payload object for a specific service, see that service’s reference page.
response An HTTP response object that configures Realm’s response to the client that called the webhook. The object has methods that allow you to set the response’s headers, body, and status code. Calling any of these methods overrides the default response behavior.

You can use the following webhook function as a base for your own webhook:

exports = async function(payload, response) {
  // Convert the webhook body from BSON to an EJSON object
  const body = EJSON.parse(payload.body.text());

  // Execute application logic, such as working with MongoDB
  if(body.someField) {
    const mdb = context.services.get('mongodb-atlas');
    const requests = mdb.db("demo").collection("requests")
    const { insertedId } = await requests.insertOne({ someField: body.someField });
    // Respond with an affirmative result
    response.setStatusCode(200)
    response.setBody(`Successfully saved "someField" with _id: ${insertedId}.`);
  } else {
    // Respond with a malformed request error
    response.setStatusCode(400)
    response.setBody(`Could not find "someField" in the webhook request body.`);
  }
  // This return value does nothing because we already modified the response object.
  // If you do not modify the response object and you enable *Respond with Result*,
  // Realm will include this return value as the response body.
  return { msg: "finished!" };
}
11

Import the Webhook

Once you have added the appropriate configuration files to the webhook subdirectory, you can import the webhook into your application.

Navigate to the root of the application directory and run the following command:

realm-cli import