├── Procfile
├── .gitignore
├── WebhookLogs
├── verifyNylasRequest.js
└── router.js
├── index.js
├── package.json
└── README.md
/Procfile:
--------------------------------------------------------------------------------
1 | web:node index.js
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .env
--------------------------------------------------------------------------------
/WebhookLogs/verifyNylasRequest.js:
--------------------------------------------------------------------------------
1 | const crypto = require("crypto");
2 | const NYLAS_CLIENT_SECRET = process.env.NYLAS_CLIENT_SECRET;
3 |
4 | // Each request made by Nylas includes an X-Nylas-Signature header. The header
5 | // contains the HMAC-SHA256 signature of the request body, using your client
6 | // secret as the signing key. This allows your app to verify that the
7 | // notification really came from Nylas.
8 | const verifyNylasRequest = async (req, next) => {
9 | try {
10 | const digest = await crypto
11 | .createHmac("sha256", NYLAS_CLIENT_SECRET)
12 | .update(req.rawBody)
13 | .digest("hex");
14 | return digest === req.get("x-nylas-signature");
15 | } catch (error) {
16 | next(error);
17 | }
18 | };
19 |
20 | module.exports = verifyNylasRequest;
21 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | require("dotenv").config();
2 | const express = require("express");
3 |
4 | const app = express();
5 | const webhookRouter = require("./WebhookLogs/router");
6 | const PORT = process.env.PORT || 4000;
7 |
8 | app.use(webhookRouter);
9 | app.use(async (req, res, next) => {
10 | req.rawBody = "";
11 | req.on("data", (chunk) => (req.rawBody += chunk));
12 | req.on("error", (err) => res.status(500).send(err));
13 |
14 | req.on("end", async () => {
15 | // because the stream has been consumed, other parsers like bodyParser.json
16 | // cannot stream the request data and will time out so we must explicitly parse the body
17 | try {
18 | req.body = await JSON.parse(req.rawBody);
19 | next();
20 | } catch (err) {
21 | res.status(500).send("Error parsing body");
22 | }
23 | });
24 | });
25 |
26 | app.listen(PORT, () => {
27 | console.log(`Listening to PORT: ${PORT} !!!`);
28 | });
29 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "webhooks-server",
3 | "version": "1.0.0",
4 | "description": "This simple express app is inspired from the example repo of [nylas-nodejs/example/webhook](https://github.com/nylas/nylas-nodejs/tree/main/example/webhooks) I made some changes as using syntax as async await, error handling using try catch, folder structures, before we used to run server locally and now we are making use of heroku to make it run in the cloud.",
5 | "main": "index.js",
6 | "scripts": {
7 | "start": "node index.js",
8 | "test": "echo \"Error: no test specified\" && exit 1"
9 | },
10 | "keywords": [],
11 | "author": "",
12 | "license": "ISC",
13 | "dependencies": {
14 | "dotenv": "^8.5.1",
15 | "express": "^4.17.1"
16 | },
17 | "repository": {
18 | "type": "git",
19 | "url": "git+https://github.com/nylas/webhooks-server.git"
20 | },
21 | "bugs": {
22 | "url": "https://github.com/nylas/webhooks-server/issues"
23 | },
24 | "homepage": "https://github.com/nylas/webhooks-server#readme"
25 | }
26 |
--------------------------------------------------------------------------------
/WebhookLogs/router.js:
--------------------------------------------------------------------------------
1 | const { Router } = require("express");
2 | const router = new Router();
3 | const verifyNylasRequest = require("./verifyNylasRequest");
4 |
5 | // Nylas will check to make sure your webhook is valid by making a GET
6 | // request to your endpoint with a challenge parameter when you add the
7 | // endpoint to the developer dashboard. All you have to do is return the
8 | // value of the challenge parameter in the body of the response.
9 | router.get("/webhook", async (req, res, next) => {
10 | try {
11 | const challenge = await req.query.challenge;
12 | return res.status(200).send(challenge);
13 | } catch (error) {
14 | next(error);
15 | }
16 | });
17 |
18 | router.post("/webhook", async (req, res, next) => {
19 | try {
20 | if (!verifyNylasRequest(req)) {
21 | return res.status(401).send("X-Nylas-Signature failed verification 🚷 ");
22 | }
23 | res.sendStatus(200);
24 | } catch (error) {
25 | next(error);
26 | }
27 | // This is the place where you want to edit on what deltas data you want to see on heroku logs.
28 | // Uncomment the below if you want to see the deltas Object on your heroku logs --tail
29 | const data = await req.body;
30 | console.log(JSON.stringify(data, null, 2));
31 | });
32 |
33 | module.exports = router;
34 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Webhooks-server
2 |
3 | This simple express app is inspired from the example repo of
4 | [nylas-nodejs/example/webhook](https://github.com/nylas/nylas-nodejs/tree/main/example/webhooks)
5 | I made some changes as using async await syntax, error handling using try catch, folder structures,
6 | before we used to run server locally and now we are making
7 | use of heroku to make it run in the cloud (Heroku).
8 |
9 | This app correctly responds to Nylas challenge request when you add a webhook
10 | url to the [developer dashboard](https://developer.nylas.com). It also verifies
11 | any webhook notification POST requests by Nylas. The aim of this repo is to be able to
12 | create a callback URL for your Nylas application to log webhook notification using heroku app.
13 |
14 | Make sure `node` and `npm` are installed on your computer.
15 |
16 | ## Initial setup
17 |
18 | - Go to your local folder where you want to save this repo
19 | - Clone this repo on your computer locally using the below command
20 | - git clone git@github.com:nylas/webhooks-server.git
21 |
22 | - Get your Client Secret which you can find on you [developer dashboard](https://developer.nylas.com) app settings you will need it later.
23 | -
24 |
25 | ## Deploy to Heroku app.
26 |
27 | - Create a heroku account here [Heroku signup](https://signup.heroku.com/login) if you don't have one.
28 | - Create a new app in your Heroku, set App name and choose your region.
29 | - Go to heroku app settings click on `Reveal Config Vars` and set up your `NYLAS_CLIENT_SECRET`
30 | -
31 |
32 | - Go to your folder locally and install heroku CLI [Install Heroku CLI](https://devcenter.heroku.com/articles/heroku-cli).
33 | - Login to heroku from your terminal with `heroku login`
34 | - Add heroku remote with `heroku git:remote -a your-heroku-app-name`, make sure you are running the command from `webhooks-server` folder locally.
35 | - Build using `git push heroku master`
36 |
37 | - You will see url as `https://your-heroku-app-name.herokuapp.com/` copy it.
38 |
39 | - Go to your [developer dashboard](https://developer.nylas.com) and set your heroku url ending with `/webhook` as a Callback URL.
40 | - Make sure you include `/webhook` in your callback Url example `https://your-heroku-app-name.herokuapp.com/webhook`
41 |
42 | 🎉 Now track all your webhooks from Nylas Dashboard Webhook logs 🎉
43 |
44 | ## Extras
45 |
46 | - If you want to see your deltas object use the below command from the terminal `heroku logs --tail`
47 |
48 | Now you will be able to see the deltas object locally.
49 |
50 |
51 |
--------------------------------------------------------------------------------