Skip to main content

AUTHORIZATION

Authorization

We support this types of authorization:

  • Google Bearer token in which you could verify that it was signed by Google with expected service account, and your Webhook's name will be specified as the audience.
  • Basic authorization, which you can verify by username and password that you specified when creating the Webhook.

Google Bearer Token

Header example

Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjE4MmU0NTBhMzVhMjA4MWZhYTFkOWFlMWQyZDc1YTBmMjNkOTFkZjgiLCJ0eXAiOiJKV1QifQ.eyJhdWQiOiJodHRwczovLzYzMzMtMTc2LTEwMC05LTgyLm5ncm9rLmlvIiwiYXpwIjoiMTAyNTM5NzAzNjAwODkwOTk2OTA4IiwiZW1haWwiOiJleGUtZW1pdC1hcGlAY2xvdWQtY29yZS1wcm9kLTJkNzYuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiZXhwIjoxNjQ0MDc4ODkxLCJpYXQiOjE2NDQwNzUyOTEsImlzcyI6Imh0dHBzOi8vYWNjb3VudHMuZ29vZ2xlLmNvbSIsInN1YiI6IjEwMjUzOTcwMzYwMDg5MDk5NjkwOCJ9.Gq40OCI5BluyItDa4gQ1gh-gaFrifdQSvjh4U3aZrInAFdfkrhcZ-VUZ9EjcGnvaKhvwETzdtFvWC30F284Vu8hc-20jgGaSJlAOoQMW0oe4PX-gPKWqlD_grDySvo4G-LwrGVLVsMorzG-GENMSoxE4CXsrHq4NH9ZmM9z5S26L1Jay6CTI6m7b2TrVOVa8qaeKyjgAOYmlgMx9CKJiPWse01zItf2XCr531V7sa6QKLgsw4DwMnPEfGfZHiG-osueKcRsoT_FRtheqHNJx6ywkAbcX5UfASN2H5h6V5m1HapeqJhZ44uR429EjTc1Gj0rxHLE0FT4xttf1G3Cb0Q

Auth examples

eyJhbGciOiJSUzI1NiIsImtpZCI6IjE4MmU0NTBhMzVhMjA4MWZhYTFkOWFlMWQyZDc1YTBmMjNkOTFkZjgiLCJ0eXAiOiJKV1QifQ.eyJhdWQiOiJodHRwczovLzYzMzMtMTc2LTEwMC05LTgyLm5ncm9rLmlvIiwiYXpwIjoiMTAyNTM5NzAzNjAwODkwOTk2OTA4IiwiZW1haWwiOiJleGUtZW1pdC1hcGlAY2xvdWQtY29yZS1wcm9kLTJkNzYuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiZXhwIjoxNjQ0MDc4ODkxLCJpYXQiOjE2NDQwNzUyOTEsImlzcyI6Imh0dHBzOi8vYWNjb3VudHMuZ29vZ2xlLmNvbSIsInN1YiI6IjEwMjUzOTcwMzYwMDg5MDk5NjkwOCJ9.Gq40OCI5BluyItDa4gQ1gh-gaFrifdQSvjh4U3aZrInAFdfkrhcZ-VUZ9EjcGnvaKhvwETzdtFvWC30F284Vu8hc-20jgGaSJlAOoQMW0oe4PX-gPKWqlD_grDySvo4G-LwrGVLVsMorzG-GENMSoxE4CXsrHq4NH9ZmM9z5S26L1Jay6CTI6m7b2TrVOVa8qaeKyjgAOYmlgMx9CKJiPWse01zItf2XCr531V7sa6QKLgsw4DwMnPEfGfZHiG-osueKcRsoT_FRtheqHNJx6ywkAbcX5UfASN2H5h6V5m1HapeqJhZ44uR429EjTc1Gj0rxHLE0FT4xttf1G3Cb0Q

Decoded auth examples

{
"aud": "https://6333-176-100-9-82.ngrok.io", // the same as 'callbackUrl' in you webhook setup in UI
"azp": "102539703600890996908", // Sender service account ID (constant)
"email": "exe-emit-api@cloud-core-prod-2d76.iam.gserviceaccount.com", // Sender service account email (constant)
"email_verified": true,
"exp": 1644078891, // when token will expire
"iat": 1644075291, // when token was issued
"iss": "https://accounts.google.com", // token issuer, constant
"sub": "102539703600890996908" // Sender service account ID (constant)
}

Token public certs

Token is signed by Google's public Certs, and you can fetch them here - https://www.googleapis.com/oauth2/v1/certs. Endpoint returns multiple certs, so you have to pick one, by kid claim in the token header.

Token Verification

To verify a token, you cloud do the following:

  • verify signature via public Google's certs
  • check aud claim, it MUST be the same as you receiving endpoint public URL
  • check email claim, IT MUST ALWAYS be exe-emit-api@cloud-core-prod-2d76.iam.gserviceaccount.com
  • check iss claim, it MUST ALWAYS be https://accounts.google.com
  • check exp claim, token MUST NOT be expired
  • DO NOT FORGET TO REMOVE BEARER prefix before verifying token

Code example (JavaScript)

import jwt from 'jsonwebtoken';
import axios from 'axios';

const token = `
eyJhbGciOiJSUzI1NiIsImtpZCI6IjE4MmU0NTBhMzVhMjA4MWZhYTFkOWFlMWQyZDc1YTBmMjNkOTFkZjgiLCJ0eXAiOiJKV1QifQ.eyJhdWQiOiJodHRwczovLzYzMzMtMTc2LTEwMC05LTgyLm5ncm9rLmlvIiwiYXpwIjoiMTAyNTM5NzAzNjAwODkwOTk2OTA4IiwiZW1haWwiOiJleGUtZW1pdC1hcGlAY2xvdWQtY29yZS1wcm9kLTJkNzYuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiZXhwIjoxNjQ0MDc4ODkxLCJpYXQiOjE2NDQwNzUyOTEsImlzcyI6Imh0dHBzOi8vYWNjb3VudHMuZ29vZ2xlLmNvbSIsInN1YiI6IjEwMjUzOTcwMzYwMDg5MDk5NjkwOCJ9.Gq40OCI5BluyItDa4gQ1gh-gaFrifdQSvjh4U3aZrInAFdfkrhcZ-VUZ9EjcGnvaKhvwETzdtFvWC30F284Vu8hc-20jgGaSJlAOoQMW0oe4PX-gPKWqlD_grDySvo4G-LwrGVLVsMorzG-GENMSoxE4CXsrHq4NH9ZmM9z5S26L1Jay6CTI6m7b2TrVOVa8qaeKyjgAOYmlgMx9CKJiPWse01zItf2XCr531V7sa6QKLgsw4DwMnPEfGfZHiG-osueKcRsoT_FRtheqHNJx6ywkAbcX5UfASN2H5h6V5m1HapeqJhZ44uR429EjTc1Gj0rxHLE0FT4xttf1G3Cb0Q
`.trim();

async function getKey(kid) {
const {data} = await axios.get('https://www.googleapis.com/oauth2/v1/certs');
if (!data[kid]) {
console.log(kid, data, data[kid]);
throw new Error('kid not found');
}
return data[kid];
}

const { header: { kid } } = jwt.decode(token, { complete: true });
const key = await getKey(kid);
console.log('Is token valid?', await jwt.verify(token, key, { algorithms: ['RS256'] }));

Optimization

EXE caches token for some time (almost an hour), so you do the same on your side. If you see that some token was already verified, and accepted in a past, you can just remember this decision, to same compute.

import { createHmac } from 'crypto';

const sharedKey = '<secret>';
const signature = 'HS256=' + createHmac('sha256', sharedKey).update(data).digest('hex');

Request example

POST /your-receiver HTTP/1.1
Host: receiving-host.example
User-Agent: Hii-Event-Gun/1.0
Content-Length: 397
Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjE4MmU0NTBhMzVhMjA4MWZhYTFkOWFlMWQyZDc1YTBmMjNkOTFkZjgiLCJ0eXAiOiJKV1QifQ.eyJhdWQiOiJodHRwczovLzYzMzMtMTc2LTEwMC05LTgyLm5ncm9rLmlvIiwiYXpwIjoiMTAyNTM5NzAzNjAwODkwOTk2OTA4IiwiZW1haWwiOiJleGUtZW1pdC1hcGlAY2xvdWQtY29yZS1wcm9kLTJkNzYuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiZXhwIjoxNjQ0MDc4ODkxLCJpYXQiOjE2NDQwNzUyOTEsImlzcyI6Imh0dHBzOi8vYWNjb3VudHMuZ29vZ2xlLmNvbSIsInN1YiI6IjEwMjUzOTcwMzYwMDg5MDk5NjkwOCJ9.Gq40OCI5BluyItDa4gQ1gh-gaFrifdQSvjh4U3aZrInAFdfkrhcZ-VUZ9EjcGnvaKhvwETzdtFvWC30F284Vu8hc-20jgGaSJlAOoQMW0oe4PX-gPKWqlD_grDySvo4G-LwrGVLVsMorzG-GENMSoxE4CXsrHq4NH9ZmM9z5S26L1Jay6CTI6m7b2TrVOVa8qaeKyjgAOYmlgMx9CKJiPWse01zItf2XCr531V7sa6QKLgsw4DwMnPEfGfZHiG-osueKcRsoT_FRtheqHNJx6ywkAbcX5UfASN2H5h6V5m1HapeqJhZ44uR429EjTc1Gj0rxHLE0FT4xttf1G3Cb0Q
Content-Type: application/json
Correlation-Id: ec580d96-4d6c-4a68-9724-c01ffa95bda1
X-Hii-Signature: HS256=65fd717df8dd1ae9c432cf0000cfda46e1143122fcfc8af944482f9771c2a9d7

{
"id": "4050752561927993",
"time": "2022-02-05T15:34:47.857Z",
"type": "exe.events.v1",
"datacontenttype": "application/json",
"data": "eyJtZXNzYWdlIjoiVGhpcyBpcyBzYW1wbGUgZXZlbnQgZGF0YSwgcmVhbCBkYXRhIGZyb20gZXZlbnQgc291cmNlIHdpbGwgZGlmZmVyIiwiY29mZmVlIjoi4piVIiwiY3VycmVudFRpbWUiOiIxOTcwLTAxLTAxIDAwOjAwOjAwIn0=",
"meta": {
"deprecationNotice": {
"removedAfter": "2022-01-31"
}
},
"source": "exe-dispatch.retailsvc.com",
"specversion": "1.0",
"dataencoding": "base64"
}

Basic Authorization

Header example

Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=

Auth examples

dXNlcm5hbWU6cGFzc3dvcmQ=

Decoded auth examples

username:password

Request example

POST /your-receiver HTTP/1.1
Host: receiving-host.example
User-Agent: Hii-Event-Gun/1.0
Content-Length: 397
Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=
Content-Type: application/json
Correlation-Id: ec580d96-4d6c-4a68-9724-c01ffa95bda1
X-Hii-Signature: HS256=65fd717df8dd1ae9c432cf0000cfda46e1143122fcfc8af944482f9771c2a9d7

{
"id": "4050752561927993",
"time": "2022-02-05T15:34:47.857Z",
"type": "exe.events.v1",
"datacontenttype": "application/json",
"data": "eyJtZXNzYWdlIjoiVGhpcyBpcyBzYW1wbGUgZXZlbnQgZGF0YSwgcmVhbCBkYXRhIGZyb20gZXZlbnQgc291cmNlIHdpbGwgZGlmZmVyIiwiY29mZmVlIjoi4piVIiwiY3VycmVudFRpbWUiOiIxOTcwLTAxLTAxIDAwOjAwOjAwIn0=",
"meta": {
"deprecationNotice": {
"removedAfter": "2022-01-31"
}
},
"source": "exe-dispatch.retailsvc.com",
"specversion": "1.0",
"dataencoding": "base64"
}