3

I have a Rails 7 SaSS app using Devise for authentication, that signs up a new user on the www.my-site.com subdomain and redirects them to the actual app after signup at dashboard.my-site.com.

I'm able to accomplish this easy enough with the following session_store.rb code:

Rails.application.config.session_store :cookie_store, key: "_myapp_session", domain: ["dashboard.my-site.com", "www.my-site.com"], tld_length: 2

But the problem is that my app allows users to have custom subdomains - which should have totally separate cookies - for example, a-customer-subdomain.my-site.com

So my thought is that I will actually need to set the :cookie_store dynamically sometime earlier - like in Middleware - so we use one setting for www and dashboard subdomain and an entirely different one for any other subdomain or domain. This is where I find myself stuck though. How can I go about making these adjustments?

D-Nice
  • 4,772
  • 14
  • 52
  • 86
  • You may try writing a custom code in the rack middleware. check this out https://stackoverflow.com/a/4065929/2488801 – wayne Jun 17 '23 at 07:50

1 Answers1

1

Looking at "What does Rails 3 session_store domain :all really do?", but also "Building a Rails App With Multiple Subdomains" by Prathamesh Sonpatki (March 2020), you should indeed use a middleware to dynamically set the cookie domain based on the incoming request.

# lib/middleware/dynamic_cookie_domain.rb
class DynamicCookieDomain
  def initialize(app)
    @app = app
  end

  def call(env)
    host = env["HTTP_HOST"].split(':').first
    Rails.application.config.session_store :cookie_store, key: "_myapp_session", domain: custom_domain(host), tld_length: 2
    @app.call(env)
  end

  private

  def custom_domain(host)
    case host
    when 'www.my-site.com', 'dashboard.my-site.com'
      ['dashboard.my-site.com', 'www.my-site.com']
    else
      host
    end
  end
end

This middleware will set the session cookie domain to ['dashboard.my-site.com', 'www.my-site.com'] if the request is coming from either of those hosts. For any other host, it will set the session cookie domain to the host of the request.

You will need to add this middleware to your middleware stack. You can do this in your application configuration:

# config/application.rb
require_relative '../lib/middleware/dynamic_cookie_domain'

module YourApp
  class Application < Rails::Application
    # ...
    config.middleware.use DynamicCookieDomain
    # ...
  end
end

This will insert the DynamicCookieDomain middleware into your middleware stack, ensuring that it is run for every request.

That should address the requirement of having different cookie settings for www and dashboard subdomains versus any other subdomain.

The custom_domain method in the middleware checks the host of the incoming request.

  • If the host is either www.my-site.com or dashboard.my-site.com, it sets the cookie domain to ['dashboard.my-site.com', 'www.my-site.com']. This means that the session cookie will be shared between these two subdomains.

  • For any other host (which would be any other subdomain or domain), it sets the cookie domain to the host of the request. This means that the session cookie will be specific to that subdomain or domain and will not be shared with www.my-site.com or dashboard.my-site.com.

This dynamic setting of the cookie domain based on the incoming request should allow you to have one setting for www and dashboard subdomains and a different setting for any other subdomain or domain.


This is slightly different from this answer, which sets the cookie domain to the second-level domain (e.g., my-site.com) if the request is coming from a subdomain, and to :all otherwise. This would share cookies across all subdomains of my-site.com.

In contrast, here, the cookie domain is set to ['dashboard.my-site.com', 'www.my-site.com'] if the request is coming from either of those hosts, and to the host of the request otherwise. This shares cookies between dashboard.my-site.com and www.my-site.com, but uses separate cookies for all other subdomains.

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250