Build a passcode protected conference line with Twilio and Ruby
Tags: twilio, ruby, rails
Published: 2020-07-28 05:20:29

---
title: Build a passcode protected conference line with Twilio and Ruby
published: true
description: Learn how to build a phone conference line protected by a passcode using Ruby on Rails and Twilio
tags: twilio, ruby, rails
cover_image: https://twilio-cms-prod.s3.amazonaws.com/images/5-84YHi1Esd5kyIbetx5HCYFZL3_esg6vvucJqB48eaoA.width-1616.png
canonical_url: https://www.twilio.com/blog/passcode-protected-conference-line-twilio-ruby
series: Conference Calls on Rails
---

We've explored [building a conference line with Ruby on Rails](https://www.twilio.com/blog/build-conference-line-twilio-ruby) before, but the result there was a conference call that anyone could join. If you want to keep your calls a little more private you will want to protect your conference lines with a passcode.

In this post we will take [the Rails application](https://github.com/philnash/conference-calls-on-rails) we previously developed and add a stage where we ask for a passcode, only allowing callers into the call if they enter it correctly.

## What you'll need

In order to build this conference application you will need:

*   [Ruby](https://www.ruby-lang.org/en/downloads/) and [Bundler](https://bundler.io/) installed
*   A Twilio account (if you don't have one yet, [sign up for a new Twilio account here and receive $10 credit when you upgrade](https://twil.io/philnash))
*   A [Twilio phone number](https://www.twilio.com/user/account/phone-numbers/incoming) that can receive incoming calls
*   [ngrok](https://ngrok.com/) for [testing webhooks with our local application](https://www.twilio.com/blog/2015/09/6-awesome-reasons-to-use-ngrok-when-testing-webhooks.html)

Once you've got all of that, we'll get started.

## Getting up and running with Rails

In [the last blog post](https://www.twilio.com/blog/build-conference-line-twilio-ruby) we built a conference application and we'll continue with that code base. If you don't already have the application, [download or clone it from GitHub](https://github.com/philnash/conference-calls-on-rails).

```bash
git clone https://github.com/philnash/conference-calls-on-rails.git -b open-conference-line
```

Install the dependencies:

```bash
bundle install
```

Start the server to make sure everything is working as expected:

```bash
bundle exec rails server
```

While the server is running you can make a `POST` request to our existing conference call webhook endpoint to see it working. It should look a bit like this:

```
$ curl --data "" localhost:3000/calls
<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Say voice="alice">Welcome to the conference call, let's dial you in right away.</Say>
  <Dial>
    <Conference>Thunderdome</Conference>
  </Dial>
</Response>
```

This response is [TwiML](https://www.twilio.com/docs/voice/twiml) and tells Twilio what to do with a call. If you set a phone number's incoming call webhook to the `/calls` endpoint in this application then anyone who calls will be welcomed and then entered into the conference call.

## Protecting a conference line

Instead of directing a caller straight into a conference call, this time we want to greet the caller and ask them for a code. When they enter the code we will check it against a code we set and if they match they will be allowed to join the conference call.

To achieve this we will use [`<Gather>`](https://www.twilio.com/docs/voice/twiml/gather) to receive their input. Let's see how that works.

First, we will need a few new actions, so generate a new controller to contain them.

```bash
bundle exec rails generate controller protected_calls
```

Open `app/controllers/protected_calls_controller.rb`, we'll add our new actions here.

For this webhook controller we need to skip the cross-site request forgery (CSRF) protection. The controller is not intended to respond to requests from users, it is for incoming webhooks from Twilio, so CSRF protection is unnecessary. Instead, check out this post on how to [protect webhook endpoints in Ruby applications by validating the request signature using Rack middleware](https://www.twilio.com/blog/2014/09/securing-your-ruby-webhooks-with-rack-middleware.html).

To skip the protection, add this to the top of the controller class:

```ruby
class ProtectedCallsController < ApplicationController
  skip_before_action :verify_authenticity_token
end
```

### Building our actions

Next, let's add an action that welcomes the user and asks them for the code. The [Twilio Ruby gem](https://www.twilio.com/docs/libraries/ruby) is already installed in this application, so we can use the TwiML helpers to build up our response.

Call the first action `welcome` and create a new `Twilio::TwiML::VoiceResponse` object to build up the response. We are gathering input from the caller, so we'll start using [<Gather>](https://www.twilio.com/docs/voice/twiml/gather) and then nest a [<Say>](https://www.twilio.com/docs/voice/twiml/say) within it. TwiML is a subset of XML, so at the end of the action we render the result as XML.

```ruby
class ProtectedCallsController < ApplicationController
  skip_before_action :verify_authenticity_token

  def welcome
    twiml = Twilio::TwiML::VoiceResponse.new
    twiml.gather(action: protected_calls_verify_path) do |gather|
      gather.say(voice: "alice", message: "Please enter the code to enter the conference followed by the hash.")
    end
    render xml: twiml
  end
end
```

`<Gather>` will listen for the user input once the message has been read out. Once the user enters the code and presses the # key Twilio will then make a request to the `action` attribute that we added. Above I used the URL `protected_calls_verify_path` which doesn't exist yet. When Twilio makes the request to the action it sends the digits that the user pressed in the `Digits` parameter of the request.

We need to build another action that will check the digits against a code we decided on before the call and use that to decide whether the caller can join the conference or if they got it wrong, direct them to enter the code again. If they can join the conference we will return TwiML with `<Dial>` and `<Conference>` to drop them into the call. Otherwise we will read out another message with `<Say>` and `<Redirect>` them back to the welcome action.

For the purposes of this application, we will add the code as an environment variable called `CONFERENCE_PIN`.

Add the following code to your controller:

```ruby
class ProtectedCallsController < ApplicationController
  skip_before_action :verify_authenticity_token

  def welcome
    twiml = Twilio::TwiML::VoiceResponse.new
    twiml.gather(action: protected_calls_verify_path) do |gather|
      gather.say(voice: "alice", message: "Please enter the code to enter the conference followed by the hash.")
    end
    render xml: twiml
  end

  def verify
    twiml = Twilio::TwiML::VoiceResponse.new
    digits = params["Digits"]
    if digits == ENV["CONFERENCE_PIN"]
      twiml.say(voice: "alice", message: "Thank you, joining the conference now.")
      twiml.dial do |dial|
        dial.conference("Vault")
      end
    else
      twiml.say(voice: "alice", message: "Sorry, that code is incorrect.")
      twiml.redirect(protected_calls_welcome_path)
    end
    render xml: twiml
  end
end
```

### Routes

We're almost done here, but we haven't sorted our routes out just yet. Open up `config/routes.rb` and add the following:

```ruby
Rails.application.routes.draw do
  resources :calls, only: [:create]
  post 'protected_calls/welcome', to: 'protected_calls#welcome'
  post 'protected_calls/verify', to: 'protected_calls#verify'
end
```

This adds `POST` routes to the 2 actions in the controller that we just created.

### Testing it all out

That's all the code we need, the next thing to do is test it. We need to start up the application with a PIN in the environment, on the command line run:

```bash
CONFERENCE_PIN=382302 bundle exec rails server
```

You can use whatever PIN code you like.

Next, we will need to use [ngrok](https://ngrok.com/) to open a tunnel and give us a public URL to this application. The server should be running on localhost on port 3000, so run the following command in another terminal window:

```bash
ngrok http 3000 --host-header "localhost:3000"
```

This will start ngrok and show you a URL you can use, it should look like `https://RANDOM_SUBDOMAIN.ngrok.io`. Grab that URL and open up your [Twilio console](https://www.twilio.com/console). We need to set our phone number's incoming call webhook to this URL plus the welcome path we just created. The whole URL we will use will be: `https://RANDOM_SUBDOMAIN.ngrok.io/protected_calls/welcome`.

Find your [phone number in the Twilio console](https://www.twilio.com/console/phone-numbers/incoming), edit it and add the URL as the incoming webhook for voice calls.

Now, dial your phone number. You will be greeted with your welcome message, enter the incorrect code and you will be denied access and asked again. Enter the correct code and you will be dropped into a conference call, waiting for anyone else who knows the code to join you.

## What else could you build?

In this post you have seen how to take user input on a phone call in order to secure a conference line. If you want to see more things you can do with conference calls, check out the [Conference TwiML](https://www.twilio.com/docs/voice/twiml/conference) docs to learn how to [join a Conference on mute](https://www.twilio.com/docs/voice/twiml/conference?code-sample=code-join-a-conference-muted-9&code-language=Node.js&code-sdk-version=3.x), [silently bridge calls](https://www.twilio.com/docs/voice/twiml/conference?code-sample=code-bridging-calls-9&code-language=Node.js&code-sdk-version=3.x), or [build a moderated conference call](https://www.twilio.com/docs/voice/twiml/conference?code-sample=code-a-moderated-conference-9&code-language=Node.js&code-sdk-version=3.x).

If you want to check out [the complete code for this application you can find it on GitHub](https://github.com/philnash/conference-calls-on-rails). I'd love to hear what you're building with Twilio too, so do hit me up on [Twitter at @philnash](https://twitter.com/philnash) or drop me an email at philnash@twilio.com.