How I Built /wat

27th Aug 2018

Making Things Wat Slack

Wat?!?!
Wat?!?!

Hey there, thanks for coming to read about how I built the the /wat Slack app. /wat is a slash command that allows you to send the Wat duck meme into the current channel... Yep, that's it! Before I get into the 'how', I think I should give you the 'why'.

Anyone who knows me, knows that for me, building something just for the sake of building it, is a good enough reason to build anything. This app has no real purpose. However, I was interested in building a Slack app and I needed something for it to do. After some quick research I discovered that a simple slash command would not take me too long to build. The idea for what exactly the slash command should do came from wanting to send the Wat duck in Slack but it not appearing in a commonly used gif inserter app. For me, this is the perfect combination of reasons to build something:

  • For the sake of building something myself - check
  • Satisfy something I've been wanting to try and learn something new - check
  • Having it fulfil some actual use for me and/or others - check

Slash Commands


For anyone unfamiliar with slash commands in Slack, they are pretty self descriptive. Typing a / into an empty message composer will open a dialog and suggest a whole load of handy commands. For quick actions without leaving your keyboard, these are indispensable.


Usage of /wat
Usage of /wat

Slack also allows third parties to add their own custom slash commands. To create a slash command for Slack, you must first have your own workspace (which you can create for free) and you must then create a new 'app'. Once you have created a new app, you can choose from a whole host of different features and functionality to add to the app. The simplest of these just so happens to be a slash command!

Registering a slash command for your app is easy, you simply provide the name for the command and a url which Slack will post to when executing your command. This is where things start to get a little more interesting. When a custom slash command is executed, Slack will make a post request to the endpoint you provide. You have probably guessed by now that if you have to provide Slack with an endpoint for your command, you need to spin up a web app to process requests from Slack. Considering discoverability isn't really an issue with this; I chose to spin up a .Net Core 2.0 app inside an Azure App Service.


Messages API


When you configure a slash command in Slack, every time the command is used in a conversation, Slack will send a post request to the endpoint you supply. This request contains rather a lot of information which can be used to drive different functionality. Information such as the the user's ID, name and workspace ID are all passed in this request. For the most basic slash command, the main parameters you are going to be interested in are command and text. The command param contains the name of the slash command emitting the request. The text param is the text immediately following the slash command, this will be any value typed by the user, but it can be used essentially to pass a space delimited set of arguments.

/command text

Once you have received a request from Slack for your slash command, you must respond with a JSON payload which Slack will use to build a message for you and insert into your conversation. Slack offers a very rich messages API which allows us to create complex messages as a response. Below is about the simplest response you can generate.

{"text": "This is a messages"}
When Slack receives this response it will generate a plain text message with the supplied text from your app and insert it into your conversation.

By default Slack will insert the response to a simple message like the above in a state where it is only visible to you. If you want your message visible to more people, you need to provide an extra visibility property. There is a huge amount of detail I could go into here about how to construct a message, however, Slack already do this pretty damn well. You can find all the details of how to format messages here.


Delayed Responses


Once you have a basic message sending to Slack you may wish to extend your app to do something more interesting or more complex. Slack has a built in timeout of 3000ms. If the response to any slash command takes longer than this, Slack will not insert its response. If your new slash command with its increased complexity takes more than 3 seconds to complete a request, you will need to use another means to respond to Slack.

In the payload for a slash command Slack provides a param called response_url. With this param, we can post a response back to Slack for this slash command. While Slack still requires that you respond to their original request within 3 seconds, it is acceptable to simply respond with a 200 status and an empty body. You can also send a response at this time if you like, Slack recommend a success message to the user may be sent explaining that their request is being processed. Slack allows the URL to be used up to 5 times within 30 minutes, the rationale being that if you need more than 30 minutes, you probably shouldn't be using a slash command to do what you want!


OAuth, Installation and Homepage


I had built /wat and was pretty happy with how it worked in my test workspace. I decided I would take a chance and submit it to Slack for listing in the public app directory. Slack have a really good process for this including handy checklists etc. I opted for a self hosted app home page which would also include the means by which to install the app.

Slack provide a handy little JS snippet which will generate the 'Add to Slack' button on your homepage. This button kicks off an oAuth installation flow which allows you to authorise /wat to access your Slack workspace. If you navigate to /wat's homepage you can see the install button at the bottom of the page.

When this button is clicked, it kicks off the oAuth flow with Slack. If you are currently logged in with Slack, you will be directed to choose which workspace you want to install the app for. Once you authorise the app, Slack will redirect back to your website with an authorisation code. At this point you will need to post this code to Slack in order to receive an Access Token and Refresh Token. Once you have successfully received these tokens, Slack will consider the app installed into the target workspace.

If you are just going to be using slash commands, you don't need to store these tokens. If your app is going to be doing something a little more complex using other extensions points in Slack, you may need to store these tokens. In the example of /wat, we don't store the tokens and have no need to.

The homepage for your app is handy as the vehicle by which you can install the app. However, it is also a requirement from Slack that you have one with basic information about the app. Further to this, Slack also insist that your apps website has a Privacy section and also a Support section with high level instructions about using your app. If you don't have these, Slack will reject your application.


Request Validation


During the process of creating this app, I submitted a few iterations to be approved by Slack. This lead to some back and forth with Slack with them testing my app and telling me why it was being rejected! After creating my apps website and verifying the install flow was working; I was sure there wasn't much else Slack would fail my app on... I was wrong!

If you are developing a slash command for Slack, simply responding to requests from Slack is enough to make your app work in dev. This leads to a slightly odd experience, which happened to me, where my app (which was working perfectly) was rejected as I was not successfully validating that requests were coming from Slack.

Slack demand two forms of validation for requests. All requests from Slack contain two Headers X-Slack-Signature and X-Slack-Request-Timestamp. Slack demand that the timestamp of each request be validated such that it is no more than 5 minutes old. In the case where it is, Slack requires that you return a 400 response.

The validation of the signature is a little more involved. Slack sign the request by computing a SHA256 HMAC of the request body. The key for this HMAC is supplied from Slack and is unique to your app. You must concatenate v0:{timestamp}:{requestBody}, compute the HMAC with the supplied key, convert to HEX and prepend v0=. You may now compare this with the signature in the request. If these are equal, then the request is valid. If not, then you must also return a 400.

Slack only demands that the requests for the slash command are validated in this way. So you don't need to worry about this for your oAuth install flow.


/wat help


Another feature that my app was rejected for not having was a help command. It is a requirement that all apps must accept a parameter of the word help and return a basic message to the user with instructions as to how to use the app. This was another thing I was not aware of and only discovered during the review process.


Wrapping Up


After validating all of the above, to my surprise, the app was accepted into the Slack public app directory listing and is now freely available to install into any Slack workspace! As of writing this /wat has received 30 installs, there have been 332 "Wat!?!?"s in its first month! Small numbers but it just keeps growing.

I hope you enjoyed reading, and I hope that in some way I have helped you with setting up your own app or inspired you to make something yourself. Also, if you want to install /wat on your own workspace, go right on ahead!


Happy Watting!
- Ian
If you enjoyed reading this article and would like to help funding future content, please consider supporting my work on Patreon.