The upcoming release of Eclipse Ditto version 2.2.0 supports HTTP connections that authenticate their requests via OAuth2 client credentials flow as described in section 4.4 of RFC-6749.

Detailed information can be found at Connectivity API > HTTP 1.1 protocol binding.

This blog post shows an example of publishing a twin event to an HTTP endpoint via OAuth2 client credentials flow. For simplicity, we will use webhook.site for both the token endpoint and the event publishing destination. Feel free to substitute them for real OAuth and HTTP servers.

Prerequisites

This example requires 2 webhooks. We will use

  • https://webhook.site/785e80cd-e6e6-452a-be97-a59c53edb4d9 for access token requests, and
  • https://webhook.site/6148b899-736f-47e6-9382-90b1d721630e for event publishing.

Replace the webhook URIs by your own.

Configure the token endpoint

Configure the token webhook to return a valid access token response. Here is an example for a token expiring at 00:00 on 1 January 3000. The field expires_in is an arbitrary big number not reflecting the actual expiration time of the access token.

  • Status code: 200
  • Content type: application/json
  • Response body:
    {
      "access_token": "ewogICJhbGciOiAiUlMyNTYiLAogICJ0eXAiOiAiSldUIgp9.ewogICJhdWQiOiBbXSwKICAiY2xpZW50X2lkIjogIm15LWNsaWVudC1pZCIsCiAgImV4cCI6IDMyNTAzNjgwMDAwLAogICJleHQiOiB7fSwKICAiaWF0IjogMCwKICAiaXNzIjogImh0dHBzOi8vbG9jYWxob3N0LyIsCiAgImp0aSI6ICI3ODVlODBjZC1lNmU2LTQ1MmEtYmU5Ny1hNTljNTNlZGI0ZDkiLAogICJuYmYiOiAwLAogICJzY3AiOiBbCiAgICAibXktc2NvcGUiCiAgXSwKICAic3ViIjogIm15LXN1YmplY3QiCn0.QUJD",
      "expires_in": 1048576,
      "scope": "my-scope",
      "token_type": "bearer"
    }
    

The access token has the form <headers>.<body>.<signature>, where <headers> and <body> are base64-encoding of the headers and the body in JSON format, and <signature> is the base-64 encoded signature computed according to the issuer’s key pair. Since the token webhook is not a real OAuth2 server, the signature in the example is a placeholder. The unencoded headers and body are as follows.

Headers

{
  "alg": "RS256",
  "typ": "JWT"
}

Body

{
  "aud": [],
  "client_id": "my-client-id",
  "exp": 32503680000,
  "ext": {},
  "iat": 0,
  "iss": "https://localhost/",
  "jti": "785e80cd-e6e6-452a-be97-a59c53edb4d9",
  "nbf": 0,
  "scp": [
    "my-scope"
  ],
  "sub": "my-subject"
}

Create the connection

Create a connection publishing twin events to the event publishing webhook using OAuth2 credentials. The tokenEndpoint field is set to the access token webhook.

{
  "id": "http_oauth2",
  "name": "http_oauth2",
  "connectionType": "http-push",
  "connectionStatus": "open",
  "uri": "https://webhook.site:443",
  "targets": [
    {
      "address": "POST:/6148b899-736f-47e6-9382-90b1d721630e",
      "topics": ["_/_/things/twin/events"],
      "authorizationContext": ["integration:ditto"]
    }
  ],
  "credentials": {
    "type": "oauth-client-credentials",
    "tokenEndpoint": "https://webhook.site/785e80cd-e6e6-452a-be97-a59c53edb4d9",
    "clientId": "my-client-id",
    "clientSecret": "my-client-secret",
    "requestedScopes": "my-scope"
  }
}

Generate a thing-created event

Create a thing granting read access to the connection’s subject. The thing-created event will be distributed to the connection for publishing.

{
  "_policy": {
    "entries": {
      "DEFAULT": {
        "subjects": {
          "{{ request:subjectId }}": {
            "type": "the creator"
          },
          "integration:ditto": {
            "type": "the connection"
          }
        },
        "resources": {
          "policy:/": {
            "grant": ["READ", "WRITE"],
            "revoke": []
          },
          "thing:/": {
            "grant": ["READ", "WRITE"],
            "revoke": []
          }
        }
      }
    }
  }
}

HTTP requests made by the HTTP connection

Before the HTTP connection publishes the thing-created event, it makes an access token request against the token endpoint to obtain a bearer token.

POST /785e80cd-e6e6-452a-be97-a59c53edb4d9 HTTP/1.1
Host: webhook.site
Accept: application/json
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials
&client_id=my-client-id
&client_secret=my-client-secret
&scope=my-scope

The request should appear at the access token webhook. The webhook should return the configured access token response.

{
  "access_token": "ewogICJhbGciOiAiUlMyNTYiLAogICJ0eXAiOiAiSldUIgp9.ewogICJhdWQiOiBbXSwKICAiY2xpZW50X2lkIjogIm15LWNsaWVudC1pZCIsCiAgImV4cCI6IDMyNTAzNjgwMDAwLAogICJleHQiOiB7fSwKICAiaWF0IjogMCwKICAiaXNzIjogImh0dHBzOi8vbG9jYWxob3N0LyIsCiAgImp0aSI6ICI3ODVlODBjZC1lNmU2LTQ1MmEtYmU5Ny1hNTljNTNlZGI0ZDkiLAogICJuYmYiOiAwLAogICJzY3AiOiBbCiAgICAibXktc2NvcGUiCiAgXSwKICAic3ViIjogIm15LXN1YmplY3QiCn0.QUJD",
  "expires_in": 1048576,
  "scope": "my-scope",
  "token_type": "bearer"
}

The HTTP connection will cache the access token and use it to authenticate itself at the event publishing webhook for each thing event, including the first thing-created event.

POST /6148b899-736f-47e6-9382-90b1d721630e HTTP/1.1
Host: webhook.site
Content-Type: application/vnd.eclipse.ditto+json
Authorization: Bearer ewogICJhbGciOiAiUlMyNTYiLAogICJ0eXAiOiAiSldUIgp9.ewogICJhdWQiOiBbXSwKICAiY2xpZW50X2lkIjogIm15LWNsaWVudC1pZCIsCiAgImV4cCI6IDMyNTAzNjgwMDAwLAogICJleHQiOiB7fSwKICAiaWF0IjogMCwKICAiaXNzIjogImh0dHBzOi8vbG9jYWxob3N0LyIsCiAgImp0aSI6ICI3ODVlODBjZC1lNmU2LTQ1MmEtYmU5Ny1hNTljNTNlZGI0ZDkiLAogICJuYmYiOiAwLAogICJzY3AiOiBbCiAgICAibXktc2NvcGUiCiAgXSwKICAic3ViIjogIm15LXN1YmplY3QiCn0.QUJD

{
  "topic": "<namespace>/<name>/things/twin/events/created",
  "headers": {},
  "path": "/",
  "value": {
    "policyId": "<policy-id>"
  },
  "revision": 1
}

The HTTP connection will obtain a new token from the access token webhook when the previous token is about to expire.

Please get in touch if you have feedback or questions regarding this new functionality.

Ditto


The Eclipse Ditto team