I created a bot to notify slack when I add a task in the task management service’s Asana.
Usually, there are many apps that can be integrated with Asana as shown in the image below, so there is almost no need to write code from 1. However, there is a limit to the apps that can be added by the company Asana and the company Slack, so I decided to write code this time.
When I tried to use Webhook, I wanted to guarantee the security, but I didn’t have any information about it, so I hope that I can be of some help to those who make applications with Asana Webhook.
Creating ‘Personal Access Token’ for Authentication
First, create a Personal Access Token for authentication.
First, you access Asana’s Developer App Console.
You can access this URL “https://app.asana.com/0/developer-console", and
you can also click “My Profile Settings” from the profile image on the upper right of the screen where you logged in with Asana, and from the pop-up “Apps” tab, click “Manage Developer Apps”.
You can obtain a token in the following format by clicking “+ New Access Token” and entering the token name:. This token is used for program and curl access.
1/1234567890123456:bive3xuos5Ohcavei4yie7ha0Oovaph8
Second, Register a Webhook
To register a Webhook, you need the Project ID where the Task will be registered and the URL to send the information when the event occurs.
You can check the ID of Project from the URL of Asana. The number in the URL when you check the list or board of the project to register the task indicates the Project ID.
In the example below, 1234567890123456
is the Project ID.
https://app.asana.com/0/1234567890123456/board
Run the curl command, substituting {access-token}
for the Access Token, {project-id}
for the Project ID, and {target-url}
for the URL to which the Webhook event should be sent.
action: added
detects additional events for the task. In addition to added
, changed
removed
deleted
undeleted
may be used.
$ curl -X POST https://app.asana.com/api/1.0/webhooks \
-H ‘Content-Type: application/json’ \
-H ‘Accept: application/json’ \
-H ‘Authorization: Bearer {access-token}’ \
-d ‘{
“data”: {
“filters”: [
{
“action”: “added”,
“resource_type”: “task”
}
],
“resource”: “{project-id}”,
“target”: “https://{target-url}”
}
}’
Third, Handshake
When the first Webhook event occurs, a request containing X-Hook-Secret
in the HTTP header for Handshake is sent to the URL set to target-url
.The registration is completed by returning a 200 OK
or 204 No Content
response to this request.
Here is the AWS Lambda code in Node.js at initial registration:. The second line logs the HTTP header X-Hook-Secret
. MEMO this X-Hook-Secret
value for later use. Also, this code is only used once when you register for the first time.
exports.handler = async (event) => {
console.log(‘this is secret header — — ->’ + event.headers[‘X-Hook-Secret’])
const response = {
statusCode: 200,
headers: {“X-Hook-Secret”: event.headers[‘X-Hook-Secret’]},
body: JSON.stringify(‘Hello from Lambda!’),
};
return response;
};
X-Hook-Secret
is a string of the form “a0ge6aChaiPhee7ioph7cucongaht3”.
You can also use this site to easily verify that this code is working properly.
https://asana-webhook-tool.herokuapp.com/
Finally, verify the requests received by Webhook
Next, the Webhook receives the data that was actually sent.
By using the X-Hook-Secret
you just got, you can verify that the request sent to the target url came from Asana and safely process the request.
Below is the AWS Lambda code using Node.js. Replace {X-Hook-Secret}
with the value you just got.
Asana sends you a request with a X-Hook-Signature
header. The value of X-Hook-Signature
is the body of the request hashed with SHA 256 HMAC using X-Hook-Secret
.
Check if the hashed value and X-Hook-Signature
are the same, and if they are, treat them as normal requests.
var crypto = require(“crypto”);
exports.handler = async (event) => {
const signature = event.headers[‘X-Hook-Signature’];
const hash = crypto.createHmac(‘sha256’, ‘{X-Hook-Secret}’)
.update(String(event.body))
.digest(‘hex’);// Check header secret
if (signature != hash) {
console.error(‘Calculated digest does not match digest from API. This event is not trusted. : ‘ + signature);
return response = {
statusCode: 401
};
}// TODO : Write code to handle Webhook dataconst response = {
statusCode: 200
};
return response;
};
This completes the basic Webhook configuration.
After checking the header, you can safely manipulate the Webhook request by processing the body of the HTTP request.
Reference Links
- Access Token : https://developers.asana.com/docs/authentication-quick-start
- Webhook : https://developers.asana.com/docs/get-multiple-webhooks
- Node.js crypto : https://nodejs.org/api/crypto.html