6

Hello this is my first post here!

I have been trying to debug this issue for a couple of days but cannot figure it out. When I am making a post request to a rails api I am getting this error I have never seen before:

Started POST "/owners" for ::1 at 2021-01-12 11:24:15 -0500
   (1.0ms)  SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC
Processing by OwnersController#create as */*
  Parameters: {"email"=>"adam", "password"=>"[FILTERED]", "owner"=>{"email"=>"adam"}}
HTTP Origin header (http://localhost:3000) didn't match request.base_url (http://localhost:3001)
Completed 422 Unprocessable Entity in 0ms (ActiveRecord: 1.8ms | Allocations: 476)


  
ActionController::InvalidAuthenticityToken (ActionController::InvalidAuthenticityToken):

Like I said I have never seen this before and I don't know how I have caused it. I have not used a proxy server and the only thing new I tried in this project that could have messed things up was I installed the devise gem but decided not to use it and deleted it.

Things I have tried:

making sure I had no pending migrations:

checking my routes:

Rails.application.routes.draw do
  resources :owners
  resources :dogs
  post 'login', to: 'sessions#create'
end

Then I thought it could be a cors issue:

require_relative 'boot'

require 'rails/all'

# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)

module Backend
  class Application < Rails::Application
    # Initialize configuration defaults for originally generated Rails version.
    config.load_defaults 6.0

    # Settings in config/environments/* take precedence over those specified here.
    # Application configuration can go into files in config/initializers
    # -- all .rb files in that directory are automatically loaded after loading
    # the framework and any gems in your application.
    config.api_only = true

    config.middleware.insert_before 0, Rack::Cors do
      allow do
        origins '*'
        resource(
          '*',
          headers: :any,
          methods: [:get, :patch, :put, :delete, :post, :options, :head]
          )
      end
    end

  end
end

I then tried googling things about invalid authenticity token and http origin header but couldn't find a helpful solution or a solution I could understand.

(last note: I tried changing it from a post request to a get request and it worked but posts cause an error)

Thanks for any advice in advance

adamadolfo
  • 65
  • 1
  • 2
  • 7
  • 3
    Are you using some http server to proxy this request to rails? Like nginx? The ports don't match between the base_url and the origin. – giraffesyo Jan 12 '21 at 16:45
  • No I saw this in my google searching. I haven't done anything like that, and never heard of proxying or nginx which is why those solutions have not been helpful. For this project I just set up a rails api and am making fetch requests to it – adamadolfo Jan 12 '21 at 16:55

3 Answers3

11

In my case, the problem was on Ngixn settings for virtual host. Found an answer at: https://github.com/rails/rails/issues/22965#issuecomment-169956605

Fix by adding more headers in Nginx (X-Forwarded-Ssl on, X-Forwarded-Port 443 and X-Forwarded-Host hostname)

This is how the section be after edit:

    location @app {
      proxy_pass http://app;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header X-Forwarded-Proto https;
      proxy_set_header X-Forwarded-Server $host;
      proxy_set_header Host $http_host;
      proxy_redirect off;
    }
Fernando Kosh
  • 3,426
  • 1
  • 34
  • 31
0

I think this is a CSRF (cross site request forgery) issue. Rails is trying to prevent invalid requests being made to your controller. It is looking for an authenticity_token on your request header, this token makes its way into the request via a hidden element in the html.erb form for post requests to a particular path. As you are using rails as an API, these tokens are absent.

There are multiple strategies for preventing this exception, and all have different security implications. Here is a good place to start: Rails API design without disabling CSRF protection

kykyi
  • 375
  • 4
  • 10
0

One solution is setting the HTTP_X_FORWARDED_HOST header to be the same value as your HTTP Origin header. The Origin header is set by the browser, in your case it'll be set to http://localhost:3000. Setting the host headers will result in your HTTP Origin matching your request.base_url. That is because the base_url is created by Rack using these headers (source code – you can see all the headers here).

The other option is to set the Rails.application.config.forgery_protection_origin_check (docs) to false. This should only be for development environments though, since you'll still want that protection in production.