Subscribers: Security and Keys

Subscriber signature

All requests sent to event subscribers will be signed by a mechanism which enables the subscribers to verify the origin of the message. The signature is a token generated by Sensedia Events Hub using a mutual-knowledge key (that is, known by Events Hub and the subscriber) that is sent during the registration of subscribers (read about sending the key below).

The signature generated will be a JWT (JSON Web Token) with the HS256 algorithm (HMAC with SHA-256), comprised of the following values:

Header:

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

Payload:

{
  "iss": "staging",
  "sub": "7f08e914-3e64-4acb-9a1e-d21f9cbabcba",
  "jti": "266dd6d0-4f21-4191-aa05-2d9833fd8eee",
  "c_hash": "0d320d3ab6b8165bc347c1ffabbe1bfd6dbe1b436df23131a8f855f35834c2cc",
  "iat": 1603894744
}

in which:

  • iss is the customerName;

  • sub is the subscriberId;

  • jti is the transactionId;

  • c_hash is the body content in SHA-256; and

  • iat is the delivery timestamp in the UTC time zone.

Signature key

A mutual-knowledge key is informed when registering a subscriber on Events Hub (read about subscriber registration here). Subscribing to events is only possible once the key is validated in the Key field.

subscribers create security
If the subscriber is unable to inform the key in time, click the icon icon refresh (which will appear) to restart time count. Once the key is validated, it is stored safely and cannot be retrieved.

JWT token

The subscriber will always receive the signature in a request header identified as x-CLIENT-webhooks-signature — with the content always transferred using Base64 encoding — regardless of whether or not they will use it for verification or if they choose to use the available security mechanisms described below in this document. That is, Events Hub will always include the signature in requests to subscribers, as in this example:

{
  "Content-Type": "application/json",
  "x-sensedia-webhooks-signature": "Y2E4MWNiMTYtNDNlNC0zZTk2LWFhZWEtNDg2MWU3NzkxZGM3"
}

The user can validate the JWT signature in their code. We’re using Java in the example below:

// Validate JWT signature

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.1</version>
</dependency>
public static Claims decodeJWT(String jwt, byte[] subscriberKey) {
    //This line will throw an exception if it is not a signed JWS (as expected)
    Claims claims = Jwts.parser().setSigningKey(subscriberKey).parseClaimsJws(jwt).getBody();
    return claims;
}
The subscriberKey in the code snippet above is the mutual key sent by a POST operation and described above.

Security token options

In addition to the signature, which is always sent, Events Hub also provides the option of sending a token to event receivers as another security requirement.

After the subscriber has registered their mutual key to generate the signature, they can choose to receive their requests with the addition of a token. There are two options: static or dynamic tokens. Both must be a hash in SHA-256 and Base64 formats.

In both cases, the subscriber also counts with the signature key for validation and assurance of the request. If a token is configured to be sent in the header, both the signature and the token will be present (the token with the name set by the user, which is security-token in the example below):

{
  "x-sensedia-webhooks-signature": "ZXlKMGVYQWlPaUpLVjFRaUxDSmhiR2NpT2lKSVV6STFOaUo5LmV5SnBjM01pT2lKemRHRm5hVzVuSWl3aWMzVmlJam9pTW1JMFlUVTJZV0V0WkdVeU55MDBPVEl6TFdFeVltTXRNbVkyTVRBMU0yVmpNamcwSWl3aWFuUnBJam9pWXprNU56UmxNekV0TURRNU1TMDBPREJoTFRrelpUWXRabVJqWlRFek1EaGlNR0V3SWl3aVkxOW9ZWE5vSWpvaVl6bGtNMkZqT0RJMU1UYzFNR1psTWpNd01EQTVPR1ptTVRWaFlUYzJOVEprTVRWbE5UQmpOemxoWXpSaVlqaGhOMlEwWWpobE1URXdOekpqTlRoaVl5SXNJbWxoZENJNk1UWXhPRFF3TlRnMU9YMC56UTVYTnpEaE5ZdU5DTVd1a0ktckZxeTkzbFFoYnRXalc2ZDNpT3dlUV9B",
  "security-token": "YWJjZGVmZmYtYXNkYXNkLWFzZC12c2JkZmRnZGYtNG1hc2Rkd2V1Z3VkYQ"
}
You may configure only one token per subscriber.

Static token

When the subscriber chooses to receive requests with a static token (which does not expire), it can be registered directly on Events Hub. Thus, a token value must be informed and it will be included in all requests.

It is worth noting that this is the simplest approach and the one that needs minimum resources and coding on the subscriber’s side (compared with dynamic tokens). However, it’s also more susceptible to attacks (such as a simple replay attack).

The token must be configured in the SECURITY step when registering/editing a subscriber, by filling these fields:

  • Type: select Static.

  • Location: where the token will be passed in the request (options: header or query param).

  • Name: name under which the value will be passed.

  • Token SHA-256: value of the token. If you wish, you can generate a random token by clicking icon token.

    subscribers create security static

Dynamic token

A dynamic token offers more security in the exchange of messages between Events Hub and subscribers when compared with a static token. A dynamic token expires and it’s completely managed by the subscriber.

When dynamic tokens are used, subscribers need to employ more resources and will be largely responsible for the ecosystem uptime. This is because Events Hub will depend on subscribers in order to obtain the tokens, which can cause messages not to be delivered. However, because the mechanism is dynamic it makes attacks harder, and it’s thus a safer option.

If the subscriber opts for this approach, they will need to provide an interface for Events Hub to obtain the token. This interface must provide an HTTP POST responsible for generating the tokens.

It’s worth highlighting that, in this approach, the subscriber should always validate the signature that is also included in token requests by Events Hub.

The interface must receive:

Header:

{
  "content-type": "application/json",
  "x-CLIENTE-webhooks-signature": "xxxxxxx"
}

Body:

{
  "type": "token"
}

The interface must return:

Header:

{
  "content-type": "application/json"
}

Body:

{
  "access_token": "<Token de acesso (hash em SHA-256 e Base64)>",
  "expires_in": "<Tempo de expiração do token em segundos>"
}

The token must be configured in the SECURITY step when registering/editing a subscriber, by filling these fields:

  • Type: select Dynamic.

  • Location: where the token will be passed in the request (options: header or query param).

  • Name: name under which the value will be passed.

  • URL OAuth: URL that generates the token.

    subscribers create security dynamic

There is no refresh token for dynamic tokens registered. The tokens will be used for the time configured by the user.
Thanks for your feedback!
EDIT

Share your suggestions with us!
Click here and then [+ Submit idea]