Modernizing the Stack Overflow for Teams app for Slack
How we improved the security, scalability, and interactivity of our app
In 2018, we released an integration between Stack Overflow for Teams and Slack. It’s now one of the most popular ways for users to interact with our platform, and we have been steadily upgrading it with new functionality based on feedback from customers. We’re pleased to announce that we’re releasing version three of our Slack integration with plenty of new features to reduce context and tool switching while streamlining the developer workflow.
With this release (available for Basic and Business today, for Enterprise in the 2021.1 release), we wanted to dig into some of the technical details of what we did. There’s a lot of great new features, and a lot of work behind the scenes to make them a reality. For reference, the integration that most people use was version two; version one was a bare-bones integration that just supported notifications (and is still used by a small fraction of Teams).
This version brings several new features that will improve your overall experience:
- A more secure and configurable authorization experience.
- Org-wide installs, so organizations with multiple Slack workspaces can add our integration to all of them at once.
- Ask questions directly from Slack with /stack ask.
- A one-click autoupdater that uses a modal dialog to make sure the app is current on all associated workspaces.
Additionally, our previous integrations were built on functionality that has since been deprecated. So the work we’ve done here sets us up to provide even more functionality in future versions.
We had originally worked with Slack to be one of their launch partners in implementing their workspace apps. When the developer preview for the feature ended, they recognized that this was the wrong path for them, and they deprecated workspace apps. While we had been planning to include features that built on workspace apps, Slack was such an incredible partner on this that we were able to pivot smoothly.They reached out and gave us a shared support channel and were incredibly responsive to our support questions. We wouldn’t have been able to implement the features in this release without them.
We had to do a fair bit of work to make sure that the new granular bot version had feature parity with what we had previously. Asking you all to upgrade only to lose functionality would have been a hard sell.
In this article, we’ll talk about how we built this new version and the path we took to ensure our new bot useful, usable, and secure.
Authentication and permissions for the granular bot
One of the primary features of the Slack integration is notifications. You can configure Stack Overflow for Teams to send a notification for a channel whenever there’s activity you are interested in.
Previously, the mechanism were used for notifications was incoming webhooks. These are URLs that we could post to whenever we wanted to send a notification to a channel. These URLs were automatically generated, so that Stack Overflow for Teams had easy access to post to any channel.
We decided to stop using incoming webhooks for a good reason: improved security. If one of these URLs returned an error, that has potential to get logged on our side. Now we (and anyone who got a hold of our logs) could spoof whatever messages they want to corporate Slack channels. For some of our more security conscious customers, this was a big no-no. They had actually asked us to disable this feature because it opened a new angle of attack.
With these updated scopes and without the incoming webhooks, we made some InfoSec teams quite happy and they were green-lighting our applications. But we still had to figure out how to get notifications sent to the right channels. Without the incoming webhook URLs, we were restricted to scopes available to our Slack bot.
For public channels, this wasn’t much of a problem. The bot just has to join all of the channels that one might want to send notifications to. We give workspace admins an opt-in setting that instructs the bot to automatically join all public channels, which has to be done one by one. It’s kind of a pain in the butt, but it worked fine on our testing environments.
Once we decided to dogfood the app and try it out on our own workspace, it broke completely. On our testing workspace, we have maybe ten channels. On our company’s workspace, we have something like 350. In stepping through these one by one and joining them, not only did it take a long time, we hit Slack’s rate limits. So we had to build a background queue on our end, which would send join messages until we saw a failure, then stop processing the queue and wait a few seconds.
But for private channels, this meant that the bot had to be manually added to a channel by a user before anyone could consider interacting with it. This may seem like an extra hassle, but it’s actually a good thing. Imagine you’ve been invited to a private channel to discuss an upcoming feature. Just revealing the name of the channel could be a massive information breach.
There’s another side effect to having to manually add the bot to channels. Imagine you have a channel with hundreds of people, something like #engineering, and you don’t want it clogged by bot spam. Admins can now exclude a bot from a channel, preventing everyone else from targeting it with notifications, no matter what their permissions, even if the channel is public.
As a result of these changes, we had to build a channel selector drop-down in Stack Overflow for Teams. This is not something we wanted to do; previously, when you were choosing which channel to send a notification to, we would send you to your Slack instance. Slack would then show you a channel selector based on your privileges. Instead, we had to create an external component that should only have access to what the bot has access to, and nothing more. Unfortunately for us, that type of scope is not currently supported by the Slack API.
Our options were to request all public channels or all private channels — separate and complimentary scopes. But both scopes are all of nothing. As we talked about earlier, just displaying some of those private channel names could be a huge problem. We don’t want to do that, and our customers don’t want us to do that. So our channel browser only has the scope to access public channels. We need to do a second check on these channels to make sure that the bot has access. Once we configure this, we can then access the bot directly to post notifications.
One install to rule them all
It’s becoming more common for large companies to have multiple Slack workspaces — one workspace for C-level execs, one for the engineers, one for sales, etc. Each of those workspaces may have their own administrator. But if you’re installing an integration with an enterprise-level piece of software like Stack Overflow for Teams, you’ll likely want that to work on every workspace in your organization. If you have ten workspaces, that’s ten installs coordinated with ten admins. Org-wide installs help to reduce the administrative burden that comes with delploy app integratiosn across multipel workspaces.
But it was worse than that. Our Enterprise customers have the option of installing our software on a local or organization-controlled server, which means the endpoint that the Slack integration interacts with will be at a different URL than normal. Admins on Enterprise installs would have to manually edit this URL in the app; we provide instructions on how to do this, but still, this makes ten edits to apps to make, ten installs on ten workspaces with ten admins. That’s exhausting.
With this release, we’re introducing org-wide installs. One person — the organization admin — can install the integration on all workspaces. If Enterprise customers need to edit the endpoint, they do so on one integration app and then install that. If the organization needs to create new workspaces, then they can make it installed by default so it already has the application baked in.
Now a single Teams user can be associated with multiple Slack workspaces, including multiple unconnected workspaces. Because of this, we had to change our database schema to support more than one workspace per user. Previously, we had one Slack access token associated with each Stack Overflow for Teams user. But now we store as many tokens as the user has workspaces in a single grid.
This can get complicated (and annoying) with a lot of workspaces in an org. In order to send notification DMs to Slack users when they are tagged in a question or otherwise need to be directly notified, we have to store a mapping of these users in addition to the access tokens. This is based on the email address, which lets us automatically map any users that match.
If a user has a different email address on Slack and Stack Overflow for Teams, then you can use the new `/stack connect` command in Slack. This gives you a link that will take you to the workspace’s associated team and allow you to link your user accounts. On the one hand, it’s not great for notifications because it adds a new requirement to map users. On the other hand, you can mention people on Slack when you create a question and that’s going to properly tag them on Stack Overflow for Teams.
Security-minded Enterprise customers have some additional new options. Those worried about storing more PII on their installation or exposing their entire company mailing lists to us can turn off the mapping feature — notifications will still work. It’s as simple as a checkbox during the install process. Some might be protective of their internal information and firewall their Enterprise environment away from the rest of the internet. For them, we allow restricting their instance to outgoing-only traffic. Only notifications will work, but it still gives us the opportunity to integrate with strictly controlled environments.
Ask directly from Slack
For this release, we also wanted tighter — and two-way — integration between Slack and Stack Overflow for Teams. To compliment notifications, you can now ask questions directly from Slack to help reduce context switching.
As you can see, this command displays a modal dialog where you can create a question with all the features as if you asked it on Stack Overflow for Teams. We had to write new code to support modals, but this modal is essentially a dumb layer that interacts with Stack Overflow for Teams APIs. The only part that is doing real time work is an autocompleter for tags. Both of these functions were part of the prep code we put in place before implementing the feature; once they worked, most of the `/stack ask` feature was easy to write.
We were able to keep most of the functionality on our side and reuse the existing post insert and post validation logic. On submit, we have the barest basic validation in the modal, checking that required fields are filled in and that they have the appropriate content lengths.
Despite being able to entirely reuse the existing post validation functionality, it turns out that the solution wasn’t so simple. At one point, one of the automated unit tests failed in a weird way. Like a lot of mysterious errors, it worked on the dev machine. However, the dev machine was set up for developing against Teams Basic and Business, while the failing test was being run against an Enterprise environment, which is code-wise closer to the public Stack Overflow site and therefore has much stricter rules around what a valid question is. In this case, the test was periodically failing because the “duplicate post” checks were triggering a warning if the unit tests were run in a specific order.
The validation logic that checks word counts, grammar, and more has to work inside of the modal. And any errors that come back from failed validations have to be visible in the modal. Those errors have to be one-to-one with what comes back from the Teams instance. Not to brag, but we did such a great job matching the behavior on both sides that it messed us up with a later automated test. Nice job, us.
Reducing friction now and forever
Chat programs like Slack are an integral part of the contemporary workplace — especially remote workplaces — so we want to make sure that the Stack Overflow for Teams experience integrates seamlessly into Slack. Requesting and providing information should be frictionless, and with this latest iteration of our Slack integration, we think the experience is even easier than before. Even with the challenge of building towards a changing paradigm, this is a better integration than before.
Of course, this won’t be our last version. The work that we put into 3.0 will pay off in future versions, and we’ll be in a better position to implement new features. For example, we’re looking at expanding on the base functionality written for modal support to add more features within Slack, such as creating and managing notifications.
We hope you enjoyed this peek under the hood of what goes on with Stack Overflow for Teams development. It’s a product that we think will make a lot of people more productive, and we look forward to making collaboration and knowledge sharing easier than ever.
This post originally appeared on The Overflow, Stack Overflow’s company blog, on January 26th, 2021.