pelargir / auto-session-timeout

Provides automatic session timeout in a Rails application.
MIT License
126 stars 63 forks source link

Can't get session params needed for redirection after timeout #48

Open pabvald opened 3 months ago

pabvald commented 3 months ago

I have a Rails application with two mountable engines: A and B. Both engines share the same authentication system based on Devise. I also use the atuo-session-timeout gem, overriding the active and timeout methods as follows:

  # GET user_sessions/active
  #
  # Returns the active status of the user.
  def active
    response.headers["Etag"] = nil # clear etags to prevent caching
    render(plain: current__user.present?, status: 200)
  end

  # GET /api/v2/user_sessions/timeout
  #
  # Redirects to the timeout path.
  def timeout
    params_h = ... # get params from cookies
    flash[:error] = I18n.t('errors.api.timeout')
    redirect_to(index_path(params_h))
  end

When a timeout occurs and the timeout method is called, I need the following parameters to redirect to the correct page:

  1. login_source: this is stored in the session and determines from which application the current user logged in (A or B).
  2. customer: the name of the customer. Different customers have different stylesheets. This can be obtained from the current user.
  3. location: which of the customer's locations was used. This can also be obtained from the current user.

However, when the timeout method is called in my sessions controller, the session has already been killed. This leaves me only one option: to store the parameters in the cookies and retrieve them from there to redirect to the correct login page.

Ideally, I would like to get these parameters from somewhere else, as cookies are being restricted more and more. In the future, if the site is embedded in an iframe, I won't even be able to get the parameters from the cookies, as they will be considered third-party cookies (see Article). This is also the case if an user has blocked all cookies in their browser.

pabvald commented 3 months ago

In the end I have customised the auto_session_timeout_js script and added the parameters, previously included in the HTML body, as query params of the timeout_path:

module AutoSessionTimeoutHelper

  # Custom implementation of [AutoSessionTimeoutHelper::auto_session_timeout_js](https://github.com/pelargir/auto-session-timeout/blob/0fa1d9f9715022c4d5badd8ab6cb61f7891dfe6c/lib/auto_session_timeout_helper.rb#L2)
  # that includes timeout params
  def custom_auto_session_timeout_js(options={})
    frequency = options[:frequency] || 60
    attributes = options[:attributes] || {}
    code = <<JS
function PeriodicalQuery() {
  var request = new XMLHttpRequest();
  request.onload = function (event) {
    var status = event.target.status;
    var response = event.target.response;
    if (status === 200 && (response === false || response === 'false' || response === null)) {
      let customer  = document.querySelector("[data-customer]").attributes["data-customer"].value
      let location = document.querySelector("[data-location]").attributes["data-location"].value
      let loginSource = document.querySelector("[data-engine]").attributes["data-engine"].value

      window.location.href = '#{timeout_path}?login_source=' + loginSource + '&customer=' + customer + '&location=' + location;
    }
  };
  request.open('GET', '#{active_path}', true);
  request.responseType = 'json';
  request.send();
  setTimeout(PeriodicalQuery, (#{frequency} * 1000));
}
setTimeout(PeriodicalQuery, (#{frequency} * 1000));
JS
    javascript_tag(code.html_safe, attributes)
  end

end

This works for parameters that can be seen by the user. However, I would still like how to do something similar without the need to hard-code the parameters in the HTML.