Class: Rack::TwilioWebhookAuthentication

Inherits:
Object
  • Object
show all
Defined in:
lib/rack/twilio_webhook_authentication.rb

Overview

Middleware that authenticates webhooks from Twilio using the request validator.

The middleware takes an auth token with which to set up the request validator and any number of paths. When a path matches the incoming request path, the request will be checked for authentication.

Example:

require 'rack' use Rack::TwilioWebhookAuthentication, ENV, //messages/

The above appends this middleware to the stack, using an auth token saved in the ENV and only against paths that match //messages/. If the request validates then it gets passed on to the action as normal. If the request doesn't validate then the middleware responds immediately with a 403 status.

Constant Summary collapse

FORM_URLENCODED_MEDIA_TYPE =

Rack's FORM_DATA_MEDIA_TYPES can be modified to taste, so we're slightly more conservative in what we consider form data.

Rack::MediaType.type('application/x-www-form-urlencoded')

Instance Method Summary collapse

Constructor Details

#initialize(app, auth_token, *paths, &auth_token_lookup) ⇒ TwilioWebhookAuthentication

Returns a new instance of TwilioWebhookAuthentication.


28
29
30
31
32
33
# File 'lib/rack/twilio_webhook_authentication.rb', line 28

def initialize(app, auth_token, *paths, &auth_token_lookup)
  @app = app
  @auth_token = auth_token
  define_singleton_method(:get_auth_token, auth_token_lookup) if block_given?
  @path_regex = Regexp.union(paths)
end

Instance Method Details

#call(env) ⇒ Object


35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/rack/twilio_webhook_authentication.rb', line 35

def call(env)
  return @app.call(env) unless env['PATH_INFO'].match(@path_regex)
  request = Rack::Request.new(env)
  original_url = request.url
  params = extract_params!(request)
  auth_token = @auth_token || get_auth_token(params['AccountSid'])
  validator = Twilio::Security::RequestValidator.new(auth_token)
  signature = env['HTTP_X_TWILIO_SIGNATURE'] || ''
  if validator.validate(original_url, params, signature)
    @app.call(env)
  else
    [
      403,
      { 'Content-Type' => 'text/plain' },
      ['Twilio Request Validation Failed.']
    ]
  end
end