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 byusername
andpassword
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 beexe-emit-api@cloud-core-prod-2d76.iam.gserviceaccount.com
- check
iss
claim, it MUST ALWAYS behttps://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"
}