Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

rails 3 sessions across subdomains not working in Internet Explorer

I am working on a rails 3 application which use subdomains. I used railscasts #221 "Subdomains in rails 3" (http://railscasts.com/episodes/221-subdomains-in-rails-3) as a guide and everything goes well, except in Explorer.

To keep my session across all the subdomains I put the next line in session_store.rb as the tutorial says:

MyApp.application.config.session_store :cookie_store, :key => '_myapp_session', :domain => "example.com"

I have tested my app on Firefox and Chrome and it works well, but for some reason is not working at all in Internet Explorer. The behavior is strange because sometimes it seems the session is share across all my subdomains, but some others there are some subdomains where I am logged in and other sudomains where I am not logged in.

I can't find any reason for this and I would appreciate any idea...

I am using Devise for authentication with rails 3.0.5

like image 635
marrossa Avatar asked Jul 26 '11 04:07

marrossa


2 Answers

I believe you'll need to change your domain value to .example.com (the leading dot indicates that the cookie can be used across subdomains):

MyApp.application.config.session_store :cookie_store, :key => '_myapp_session', :domain => ".example.com"
like image 174
Dave Avatar answered Sep 28 '22 09:09

Dave


For some reason this did not work (rails 3.2.11) for any session data that was set on a subdomain. It took a piece of custom Middleware to fix it. A summary of that solution is below.

tl;dr: You need to write a custom Rack Middleware. You need add it into your conifg/environments/[production|development].rb. This is on Rails 3.2.11

Cookie sessions are usually stored only for your top level domain.

If you look in Chrome -> Settings -> Show advanced settings… -> Privacy/Content settings… -> All cookies and site data… -> Search {yourdomain.com} You can see that there will be separate entries for sub1.yourdomain.com and othersub.yourdomain.com and yourdomain.com

The challenge is to use the same session store file across all subdomains.

Step 1: Add Custom Middleware Class

This is where Rack Middleware comes in. Some relevant rack & rails resources:

  • Railscasts about Rack
  • Railsguide for Rack
  • Rack documentation for sesssions abstractly and for cookie sessions

Here is a custom class that you should add in the lib This was written by @Nader and you all should thank him

# Custom Domain Cookie
#
# Set the cookie domain to the custom domain if it's present
class CustomDomainCookie
  def initialize(app, default_domain)
    @app = app
    @default_domain = default_domain
  end

  def call(env)
    host = env["HTTP_HOST"].split(':').first
    env["rack.session.options"][:domain] = custom_domain?(host) ? ".#{host}" : "#{@default_domain}"
    @app.call(env)
  end

  def custom_domain?(host)
    host !~ /#{@default_domain.sub(/^\./, '')}/i
  end
end

Basically what this does is that it will map all of your cookie session data back onto the exact same cookie file that is equal to your root domain.

Step 2: Add To Rails Config

Now that you have a custom class in lib, make sure are autoloading it. If that meant nothing to you, look here: Rails 3 autoload

The first thing is to make sure that you are system-wide using a cookie store. In config/application.rb we tell Rails to use a cookie store.

# We use a cookie_store for session data
config.session_store :cookie_store,
                     :key => '_yourappsession',
                     :domain => :all

The reason this is here is mentioned here is because of the :domain => :all line. There are other people that have suggested to specify :domain => ".yourdomain.com" instead of :domain => :all. For some reason this did not work for me and I needed the custom Middleware class as described above.

Then in your config/environments/production.rb add:

config.middleware.use "CustomDomainCookie", ".yourdomain.com"

Note that the preceding dot is necessary. See "sub-domain cookies, sent in a parent domain request?" for why.

Then in your config/environments/development.rb add:

config.middleware.use "CustomDomainCookie", ".lvh.me"

The lvh.me trick maps onto localhost. It's awesome. See this Railscast about subdomains and this note for more info.

Hopefully that should do it. I honestly am not entirely sure why the process is this convoluted, as I feel cross subdomain sites are common. If anyone has any further insights into the reasons behind each of these steps, please enlighten us in the comments.

like image 37
Evan Avatar answered Sep 28 '22 10:09

Evan