2

I am setting up React SPA (www.mysite.com) and Rails API (api.mysite.com) app. When I use same URL name everything works as expected, however when URL names are different, the web browser is not setting site cookie. With cookies missing, CSRF validation also fails of course. So for example if SPA App runs on localhost and Rails API App on localhost:3000 all good, the problem is only when I use the intended DNS names.

Sounds like a CORS problem but I can’t find where for many days now…

Here is my config:

Rails side I am using rack-cors ruby gem

config/initializers/cors.rb

Rails.application.config.middleware.insert_before 0, Rack::Cors do
   allow do
     origins 'localhost’,  'www.mysite.com',

     resource '*',
       headers: :any,
       credentials: true,
       methods: [:get, :post, :put, :patch, :delete, :options, :head]
   end
end

Rails.application.config.action_controller.forgery_protection_origin_check = false

on React side I have axios config as follows:

src/App.js

axios.defaults.xsrfCookieName = "CSRF-TOKEN";
axios.defaults.xsrfHeaderName = "X-CSRF-Token";
axios.defaults.withCredentials = true;

When React App starts, it makes a GET request to the API backend to grab CSRF token for later use. In the same time browser is supposed to set site cookies.

    axios
        .get("/sessions/csrf_token", {
          headers: { "Content-Type": "application/json"
          },
        })
        .then(response => {
          // do stuff
          });
        });

The response headers look the same in both cases when site cookies are set and missing

enter image description here

I can also see cookies are sent to the browser and yet they are missing under Cookies section

enter image description here

Any thoughts on what I can be missing here are very much appreciated!!! Thanks!!

UPDATE:

I also should have mentioned that my session config file is set to allow subdomains

config/initializers/session_store.rb

Rails.application.config.session_store :cookie_store, key: '_mysite_session', expire_after: 8.hours, domain: :all, tld_length: 2

Possibly something else is wrong with my cookies config, but I can't figure out where to look at and what other settings should be checked.

Here is a screenshot of my Cookies pane when I use localhost and cookies are retained in the browser as expected:

enter image description here

When I use www.mysite.com and api.mysite.com names, the pane on the right is just empty.

sideshowbarker
  • 62,215
  • 21
  • 143
  • 153
alikk
  • 373
  • 4
  • 9
  • This is somewhat of a shot in the dark but have you tried specifying the second domain without the WWW in your rack-cors config? Also is there anyway we could get a picture of your browser cookies pane and of the source code with those real domains you were talking about? – sevensidedmarble Apr 09 '20 at 14:00
  • @sevensidedmarble I've tried domain without www to no success. In general if CORS settings are misconfigured in any way, axios simply doesn't get a back a valid response. In my case I see no error and API call returns a valid JSON response. The only problem is my cookies pane is empty. Let me add an update to the post itself with a screenshot of what I expect the cookies pane to look like – alikk Apr 09 '20 at 14:34
  • I think I may have figured it out, check out my answer below. – sevensidedmarble Apr 09 '20 at 15:01

2 Answers2

1

I've been looking into this and I think this may be relevant to what you're seeing:

Share cookie between subdomain and domain

Apparently if you don't specify a domain in the set-cookie header, the cookie is considered "host only". So you might have to have it look like:

Set-Cookie: name=value; domain=mydomain.com

I'm sure this is doable with Axios.

sevensidedmarble
  • 537
  • 1
  • 3
  • 12
  • So my problem is Rails doesn't send domain information with cookies. This should be handled by Rails.application.config.session_store line from above, but it is not happening for some reason. I can manually set custom cookie with the domain attribute and then it appears in Cookies pane. Now I need to figure out why Rails doesn't do it globally... Thank you for your help! – alikk Apr 09 '20 at 19:34
1

I had the same problem. I fixed this, setting a domain for cookies.

In ApplicationController, when you set CSRF-TOKEN do the follows

cookies["CSRF-TOKEN"] = {
  value: form_authenticity_token,
  domain: ".mysite.com"
}

And in config/application.rb add the domain too config.middleware.use ActionDispatch::Session::CookieStore, domain: ".mysite.com"

I hope that this answer helps you