Skip to content

Crossdomain authentication

Petr Mlčoch edited this page Nov 24, 2023 · 2 revisions

Folio uses Folio::Devise::CrossdomainController concern to enable one user account to use at many sites. Authentication is done at MASTER site. All SLAVE sites sign in pages are redirected (if needed) to MASTER.

That behavior requires Rails.application.config.folio_crossdomain_devise = true initializer setting,including Folio::Devise::CrossdomainController in authentication controllers and overriding Folio.site_for_crossdomain_devise(to return master site)

Than master site is used to manage users.

Flows goes like this:

  1. TARGET SITE 1

    1. Going to target site homepage will trigger CrossdomainHandler.new.handle_before_action! with :noop result. So page is displayed.

    2. Going to sign in page of target site (TSI) will kick in crossdomain controller concern, so it will call CrossdomainHandler.new.handle_before_action!

    3. CrossdomainHandler will check presence of params[:crossdomain] (not present now) and calls its authenticate_user_on_slave_site!.

    4. That will

      1. (re)set key folio_devise_crossdomain into target site session "folio_devise_crossdomain":{ "token":"MH8x1xh8fqK_sQPnN7Ku", # <= newly generated "timestamp":"2023-11-23T10:43:30.910+01:00", "resource_name":"user"}}.
      2. return result :redirect_to_master_sessions_new, along with params to pass { only_path: false, host: master_site.env_aware_domain, crossdomain: "MH8x1xh8fqK_sQPnN7Ku", site: target_site.slug, resource_name: :user, }
    5. Controller will redirect to master site user sign in page (MSI) with such params

  2. MASTER CROSSDOMAIN SITE

    1. MSI will also calls CrossdomainHandler.new.handle_before_action!
    2. CrossdomainHandler will try to read token = params[:crossdomain] (no session on master site yet) and target_site_slug = params[:site]
      • if they are not present, it will return :noop and controller will proceed with controllers sign_in action
      • if they are present (and they are now), it will setup key folio_devise_crossdomain into master site session with
         "folio_devise_crossdomain":{
           "target_site_slug":"target_site_slug",
           "token":"MH8x1xh8fqK_sQPnN7Ku",
           "resource_name":"user",
           "redirected_to_sessions_new":true}
         }
        
        and return :noop to controller. Controller proceed with sign_in action.
    3. User will fill credential and POST them to MSI.
    4. MSI will sign in user, creating current_user instance.
    5. Than CrossdomainHandler.new.handle_before_action! is called, which will RESET curren_user.crossdomain_devise_token = "newly_generated_value" and current_user.crossdomain_devise_set_at = Time.current. And return sign_in_on_target_site (which leads to redirecting back to TSI).
    6. Controller redirect to TSI with params crossdomain=MH8x1xh8fqK_sQPnN7Ku&crossdomain_user=newly_created_value
  3. BACK TO TARGET SITE 1

    1. TSI will trigger again CrossdomainHandler.new.handle_before_action! with params crossdomain (already in target site session) and crossdomain_user (new to target site).
    2. Crossdomain handler will check these params validity and finds user according to user.crossdomain_devise_token == params[:crossdomain_user]. If it exists, key folio_devise_crossdomain is deleted from target site session and :sign_in (with found user along) is returned to controller.
    3. Controller will do devise own sign_in(result.resource_name, result.resource), setting current_user (as session key "warden.user.user.key":[[17257],"$2a$11$yStwNX1YFKa4QcbkjM0PGedb628873480393b98cf901d6d1d4a95d"]) and redirect to after_sign_in_path_for(result.resource).
    4. User is signed in (by devise) at target site, and whenever CrossdomainHandler.new.handle_before_action! is called on target site, :noop is returned
  4. ANOTHER SLAVE SITE (TARGET 2)

    1. When user comes to another slave site (target2), it is signed out. CrossdomainHandler.new.handle_before_action! will return :noop result.
    2. Going to target2 sign in page (TSI2) triggers CrossdomainHandler.new.handle_before_action! and that will reset folio_devise_crossdomain key in target2 session and returns :redirect_to_master_sessions_new (note difference: at 4.1 we are not in devise controller, at 4.2 we are at devise controller).
    3. TSI2 will redirect to master site user sign in page (MSI) with new set of params crossdomain=CoH_qv7rka1dA4TaKz-C&resource_name=user&site=target2-site
  5. MASTER SITE AGAIN

    1. Master site will load current_user and run CrossdomainHandler.new.handle_before_action!.
    2. That will RESET user.crossdomain_devise_token = "newly_generated_value2" and user.crossdomain_devise_set_at = Time.current and returns :sign_in_on_target_site.
    3. Master site controller will redirect back to TSI2 with params crossdomain=CoH_qv7rka1dA4TaKz-C&crossdomain_user=newly_generated_value2
  6. BACK TO TARGET 2 SITE

    1. Return to TSI2 continues in same manner as 3.1-3.4. So user is signed in at Target site 2 automagicaly.
  7. SIGN OUT ON ANY SLAVE SITE

    1. Sign out on any of Target sites will lead to sign out on all sites.