Sinatra how use Rack::Protection::AuthenticityToken except for certain api routes

467 views Asked by At

I am trying to configure a classic Sinatra 2.0.8.1 app ("www.example.com") to use Rack::Protection, and especially Rack::Protection::AuthenticityToken, on some but not all routes.

Internal forms (within the app) work fine. Each form has a hidden CSRF authenticity token, so the forms in the app can POST data to routes in the app.

However I cannot find any documentation how to EXCEPT or SKIP AuthenticityToken for certain routes so that external apps can POST data to this app.

In this case we have a few routes to which two of our other apps ('foo.example.com' and 'bar.example.com') POST data to. But when we implemented Rack::Protection::AuthenticityToken all of those routes now return a 403 when posted to.

I've tried a variety of things such as permitted_origins and origin_whitelist as shown below, but no external app can POST data to the Sinatra app unless I disable Rack::Protection::AuthenticityToken for the entire app.

# foo.example.com
# doesnt work:
require 'rack/protection'
use Rack::Protection, permitted_origins: ["https://foo.example.com", "https://bar.example.com"]
set :protection, :origin_whitelist => ['https://foo.example.com', 'https://bar.example.com'], except: [:remote_token, :frame_options, :path_traversal] 
use Rack::Protection::AuthenticityToken
use Rack::Protection::RemoteReferrer

Surely there is some mechanism for "omitting" the requirement for a CSRF token on certain routes, such as api routes that receive POSTed data?

1

There are 1 answers

0
jpw On BEST ANSWER

Although the solution makes me feel dirty, here's what worked:

  1. put all routes in their own file/class (kind of like controllers in Rails)

  2. the (api) routes that I wanted to NOT use a CSRF token, I use THAT class file before I do the Rack protection initializations.

  3. The classes containing the (normal) routes I DO want to protect from CSRF gets use after the Rackprotection initialization.

use Rack::Protection
set :protection,  except: [:path_traversal]

# FIRST LOAD ROUTES *NOT* PROTECTED BY Rack::Protection::AuthenticityToken

use ApplicationController
use ApipostController # external POST routes to omit 

# NOW enable the AuthenticityToken protection

Rack::Protection::AuthenticityToken
use Rack::Protection::AuthenticityToken
use Rack::Protection::RemoteReferrer

# now LOAD NORMAL ROUTES TO BE PROTECTED BY Rack::Protection::AuthenticityToken

use FooController 
use BarController