Use Slack's Incoming Webhooks from your Rails app

Incoming Webhooks are the simplest way to post messages from your application into your users' Slack channels. They use plain HTTP requests with JSON payloads to post text messages and rich content alike.

If you're building a Slack app, with Rails, you probably want to make use of incoming webhooks to send custom message notifications about your app. To do this, we'll authenticate your app to your user's Slack team and extract the incoming webhook URL from the API.

Embed the "Add to Slack" button

If you haven't already registered your app with Slack, go to the Your Apps page and click "Create New App". Give your app a name and click "Create App".

Create an App

After you've created your app, head over to the Slack Button documentation page and scroll down to the "Add the Slack button" section. There you'll find a form where you can customize the code for embedding your Slack button. Be sure to select your app name from the list. Also be sure the "incoming webhook" option is selected.

Add the Slack Button

Paste the resulting code into the view where you want your user to authenticate their Slack team with your application. You'll most likely want this to occur after the user has already authenticated themselves with your app so they'll be able to log back in and change their preferences.

Create a callback endpoint

When your users click the "Add to Slack" button, they'll be taken to a Slack-hosted page where they'll verify that they want to give you the ability to post to Slack on their behalf. After they confirm, Slack will redirect to an OAuth Redirect URL. This URL will receive a special code from Slack that will grant your app access to Slack's API features, including incoming webhooks.

Before we build the endpoint, add the Slack API gem to your Gemfile. I came across two popular gems at the time of this writing. The one we'll use is the slack-api gem:

# Gemfile
gem 'slack-api'

Run bundle install to download the gem and load it into your app.

Next, define a route in your routes.rb file for our new endpoint:

# config/routes.rb
Rails.application.routes.draw do
  # ...
  get '/auth/callback', to: 'slack#callback'
end

Then, create a corresponding controller in app/controllers:

# app/controllers/slack_controller.rb
class SlackController < ApplicationController
  # If you're using Devise to authenticate your
  # users, you'll want to first ensure you
  before_action :authenticate_user!

  def callback
    client = Slack::Client.new
    response = client.oauth_access(
      client_id: <YOUR_SLACK_CLIENT_ID>,
      client_secret: <YOUR_SLACK_CLIENT_SECRET>,
      code: params[:code],
      redirect_uri: "http://localhost:3000/auth/callback"
    )

    if current_user.update_attributes(
      slack_access_token: response['access_token'],
      slack_incoming_webhook_url: response['incoming_webhook']['url']
    )
      redirect_to root_path
    else
      render text: "Oops! There was a problem."
    end
  end
end

First, we create a before_action which authenticates the user before entering the controller action. It's likely you'll want to know who is clicking the "Add to Slack" button so you're able to save their Slack credentials for later use and/or discarding.

Then, in the action, we create a new Slack::Client object and call the Slack API method oauth.access which will grant us access to the Slack access token, incoming webhook URL, and other metadata associated with the Slack account we just authorized.

You'll want to change the client_id and client_secret settings to reflect the settings in your Slack app's configuration.

Slack App Credentials

Since we defined the route to our callback as /auth/callback in our routes file, you should use http://localhost:3000/auth/callback (or a different port if you're running Rails elsewhere) as the redirect_uri value. Note that you'll want to make this configurable when you deploy this to production.

You'll also want to add http://localhost:3000/auth/callback to the redirect URL field in your Slack app config panel:

Slack OAuth Settings

After we call oauth_access, we then update our current_user record's slack_access_token and slack_incoming_webhook_url attributes with the values in the API response. You might want to store them differently in your app, so I've added this purely for illustration. But you'll want to store them somewhere so you're able to access them when we post messages using the incoming webhook.

Send a message using the webhook

We've successfully authorized our Rails app to use the Slack API on behalf of our user. Now let's post a message using the incoming webhooks API!

For demonstration, let's build an endpoint at /post_message which posts the message "Hello, Slack!" into the user's Slack when we visit it.

First, add a route declaration:

# config/routes.rb
Rails.application.routes.draw do
  # ...
  get '/auth/callback', to: 'slack#callback'
  get '/post_message', to: 'slack#post_message'
end

We're going to use the Faraday gem as our HTTP client. Any HTTP client gem will do, since the incoming webhook is just a plain HTTP request. Add it to your Gemfile:

# Gemfile
# ...
gem 'faraday'

And add a new controller action to SlackController:

class SlackController < ApplicationController
  # ...

  def post_message
    conn = Faraday.new(url: current_user.slack_incoming_webhook_url)

    conn.post do |req|
      req.headers['Content-Type'] = 'application/json'
      req.body = { text: "Hello, Slack!" }.to_json
    end

    render text: "Posted to Slack!"
  end
end

First we create a new Faraday connection with the URL we captured in our callback action. Then, we post to the endpoint using a JSON request body. The payload of the request is formatted according to the specification in the Slack Incoming Webhooks documentation. Finally, we render some text to let the user know we posted to Slack.

We ought to do more error handling in the event Slack doesn't respond, but I'll leave that as an exercise for the reader.

Assuming everything is wired up, when you point your browser at http://localhost:3000/post_message, you'll find a new message waiting for you in Slack!

I had a tough time sifting through the Slack documentation to find a decent Rails walkthrough, so I hope this guide answers some of your questions.