Was this page helpful?

Using app identities and events

App identities and events enable you to create custom backend applications that extend Contentful. For an app to interact with Contentful’s APIs outside the web app, it needs to request a valid access token. This article will walk you through creating an app that uses identities and events to add default values to entries.

You can also watch this video outlining the steps below:

Table of contents

Getting up and running

Most of the actions described in this tutorial can only be performed by organization owners, admins or developers.

Things you will need

  • Git
  • An up-to-date version of Node.js
  • ngrok, or another way to host the app. ngrok is a tool that allows applications running on localhost to be available to the public internet. For this tutorial, we’ll use it to make the app available to receive app events.

Set up process

These steps will guide you through setting up app identities and events for a Contentful app. You can use them if you’d like to understand the process. However, you can skip the set up with a script that’s included in the demo.

Getting the demo app code

Clone the Contentful apps repository to get the code for the demo app.

git clone https://github.com/contentful/apps

Creating the app definition

Create a new AppDefinition to make your app installable in the space-environments within your organization. To do this, navigate to the Apps tab in your organization’s settings in the web app and click Create app. You only need to enter a name for now.

Create app dialog

Creating your app keys

Next, we’ll make a key pair, consisting of a public and a private key. It will be used by your app’s backend to request access tokens for its installations.

  1. On the same page as before, navigate to the Key pairs tab, which should have appeared after creating your app definition. This page contains a list of keys you created.
  2. Click on the Generate key pair button. After the keys have been generated, the private key will be downloaded to your device. The appropriate public key will be automatically stored by Contentful and should show up in the key list on the page. In case you already have a key pair that you want to use, you can instead use the upload a public key link on the same page, and then paste your public key into the dialog. Contentful's app keys UI
  3. Move the private key into the apps repository, so that it can be used by the app.
    # Navigate into the project folder
    cd apps/examples/default-values-backend
    # Move the key
    mv <path/to/downloaded/private-key> ./keys/key.pem

Subscribing to app events

App events allow apps to subscribe to changes in Contentful entities, similarly to webhooks. App events are linked to a specific app definition and will be sent for each space-environment that an app is installed into.

To define which events your app subscribes to, you’ll need to know where your app will eventually be hosted. Contentful then POSTs to that URL when the events take place.

Hosting the app

If you want to test app identities and events quickly, we recommend using ngrok. It’s a tool that allows you to make your localhost accessible from the public internet.

Download ngrok if you haven’t already, then invoke the following:

# Use 3543, as that is the port where the demo app will run
ngrok http 3543

You’ll see a status screen that includes the URL where ngrok has made your localhost available. Note down the HTTPS URL.

Navigate back to your app definition in the organization settings. Within the Events tab, enable events for your app and add your ngrok URL. Then select the Entry | Create action in the topics selection matrix. It will look like this:

app event configuration

Installing the app

To use the app, you’ll need to install it into a space-environment.

To do that, click Install to space at the top right of the app definition settings or navigate to the Apps tab within a space-environment.

Creating a content type for the app

As the app will be used to set default values to entries, you’ll need a content type. If you already have a content type that you want to use, note its ID and skip the rest of this step.

Otherwise, navigate to the content model in the space-environment where your app is installed and click Add content type at the top right of the screen.

Name your content type whatever makes the most sense for you, but please ensure to add a field with an ID of “title”. a content type’s id

Once your content type is created, note down its ID. You’ll need it in the next step.

A content type’s ID can be seen in the sidebar on the right of the screen. a content type’s id

Running the app

If you’ve followed the above steps, ngrok should make localhost:3543 available to the public internet.

Update the .env file in the demo app’s folder with a few pieces of information to run the app:

APP_ID= the app id you noted down earlier
CONTENT_TYPE_ID= the content type id you noted down earlier

At this point, you can run the app with:

yarn && yarn start

Now, let’s see how the app looks in action!

Testing the app

If you go into the Contentful web app and create a new entry of the content type you set up earlier, you will see a default value inserted into the title field shortly after creation by your app.

Code breakdown

You’ve seen how to set up app identities and events, and played around with them. Now, let’s look at the code to see how it works.

The code presented below is edited to show only the parts that are important to this tutorial. If you’d like to get an overview of the code, find it in examples/default-values-backend/src/index.ts or directly on Github).

First, let's look at how our code authenticates with Contentful.

To let Contentful know that the backend really belongs to the app developer, we use our private key to sign a JSON Web Token (JWT). This token is used to request an app access token, which allows the app to interact with Contentful’s Content Management API.

In our example, this is all handled through the node-apps-toolkit, an NPM package that provides convenient tooling for app creators.

const appAccessToken = await getManagementToken(privateKey, {
  appInstallationId: APP_ID,
  spaceId,
  environmentId,
});

If you'd like to replicate this process in another language, or simply learn more about it, you can take a look at the code here.

The app access token will only be valid for a short time period (10 minutes). In a production application we would save the token between requests, and create a new one only once it expires. Because we are using node-app-toolkit, this behavior is already included.

Now, let’s take a look at a route handler that is listening to app events. This will be called whenever a piece of content is created in a space-environment where the app is installed.

const addDefaultData = (appToken: string) => ({
  method: "POST",
  path: "/event-handler",
  handler: async (request: Hapi.Request, h: Hapi.ResponseToolkit) => {
    try {
      // First we extract the Entry id and version from the payload. We'll need
      // these to determine if this is an Event for the sort of Content that we
      // are interested in.

      const { id, version, contentType, space, environment } = request.payload.sys;

      // We also retrieve the space and environment IDs, as we will need these
      // to create the app access token.
      const spaceId = space.sys.id;
      const environmentId = environment.sys.id;


      console.log(`Received webhook request because Entry ${id} was created`);

      if (contentType.sys.id !== CONTENT_TYPE_ID) {
        // If the content type does not match the one we created in setup, we just
        // ignore the event
        console.log(
          `Entry's content type: ${contentType.sys.id} did not match the content type created for the App, ignoring`
        );
        return h.response("success").code(204);
      }

      // Now we use the private key to get an App Access Token
      // The app can use this to interact with the CMA in the space-environment of the app installation.
      // The token is internally cached until it expires after 10 minutes.
      const appAccessToken = await getManagementToken(privateKey, {
        appInstallationId: APP_ID,
        spaceId,
        environmentId,
      });

      // Then we make a request to contentful's CMA to update the Entry with our
      // default value.
      const res = await fetch(
        `${BASE_URL}/spaces/${spaceId}/environments/${environmentId}/entries/${id}`,
        {
          method: "PUT",
          headers: {
            Authorization: `Bearer ${appAccessToken}`,
            "X-Contentful-Content-Type": contentType.sys.id,
            "Content-Type": "application/json",
            "X-Contentful-Version": version,
          },
          body: JSON.stringify({ fields: { title: { "en-US": "a default value" } } }),
        }
      );

      if (res.status === 200) {
        console.log(`Set default values for Entry ${id}`);
        return h.response("success").code(204);
      } else {
        throw new Error("failed to set default values" + (await res.text()));
      }
    } catch (e) {
      console.error(e);
      throw new Error(e);
    }
  },
});

Conclusion

In this tutorial, you saw how to set up app identities and events. The app we created listens to app events and interacts with Contentful’s Content Management API using an app access token.

Why not take a look at the other app events for ideas on how to extend this app for different use cases. There are lots of possibilities, and we can’t wait to see what you come up with! Share your feedback or show off your app in our Slack community.