Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

POST from Slack for button interactions has empty body

I'm setting up a Slack bot using node.js. The event system works perfectly and gives me POSTs with valid bodies from Slack, and I am able to successfully send messages (both interactive and not) to Slack.

However, the POSTs Slack sends me in response to an interaction with the buttons on interactive messages has an empty body. Interestingly, the Slack headers are still well-formed, although it fails to pass the signing secret test (which I know I implemented properly since event POSTs from Slack pass it).

I've set up everything for interactions according to Slack's own documentation here: https://api.slack.com/messaging/interactivity/enabling. I'm using express, request, and XMLHttpRequest to receive and send HTTP methods. If anyone has encountered this problem or has any insights, that would be great. Thanks!

Here's a code snippet for my function receiving POSTs from interactions:

var express = require('express');
var request = require('request');
var XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest;
var bodyParser = require('body-parser');
var app = express();
app.use(bodyParser.json());

app.post('/interaction', (req, res) => {
    res.sendStatus(200);
    var payload = {
            "channel": req.body.payload.channel, // Breaks here since req.body is empty
            "text": "Selected choice " + req.body.payload.actions.text.text
        }

    var r = new XMLHttpRequest();
    r.onload = () => { var status = request.status; var data = request.responseText; }
    r.open("POST", request_url, true);
    r.setRequestHeader("Content-Type", "application/json");
    r.setRequestHeader("Authorization", "Bearer " + botToken);
    r.send(JSON.stringify(payload));
});
like image 269
electricsheep Avatar asked Jun 13 '19 14:06

electricsheep


1 Answers

The Slack documentation doesn't seem to mention this, but empirically it would seem that the content type for webhook calls to apps uses Content-Type: application/x-www-form-urlencoded. You'll want to add:

app.use(bodyParser.urlencoded({ extended: true }));

In addition, the payload parameter can't be accessed as you're doing: it's actually a JSON object serialized as a string. This is documented here: https://api.slack.com/messaging/interactivity/enabling#understanding_payloads

The request will be made to your specified request URL in an HTTP POST. The body of that request will contain a payload parameter. Your app should parse this payload parameter as JSON.

So your code will want to do something like this:

var slack_payload = JSON.parse(req.body.payload);
var payload = {
            "channel": slack_payload.channel,
            "text": "Selected choice " + slack_payload.actions.text.text
        }
like image 183
ahl Avatar answered Nov 14 '22 21:11

ahl