Is there a Rack middleware for using sessions without cookies? Is there a Rack middleware for using sessions without cookies? ruby ruby

Is there a Rack middleware for using sessions without cookies?


Rack can use custom session ID items instead of cookies:

require 'rack/session/abstract/id'

The Rack documentation may be a helpful place to start your search. I believe you're looking for the "skip" option (or "defer" option).

Docs:

ID sets up a basic framework for implementing an id based sessioningservice. Cookies sent to the client for maintaining sessions will onlycontain an id reference. Only #get_session and #set_session arerequired to be overwritten.

All parameters are optional.

  • :key determines the name of the cookie, by default it is'rack.session'
  • :path, :domain, :expire_after, :secure, and :httponly set the relatedcookie options as by Rack::Response#add_cookie
  • :skip will not a set a cookie in the response nor update the session state
  • :defer will not set a cookie in the response but still update the sessionstate if it is used with a backend
  • :renew (implementation dependent) will prompt the generation of a newsession id, and migration of data to be referenced at the new id. If:defer is set, it will be overridden and the cookie will be set.
  • :sidbits sets the number of bits in length that a generated sessionid will be.

These options can be set on a per request basis, at the location ofenv['rack.session.options']. Additionally the id of the session can befound within the options hash at the key :id. It is highly notrecommended to change its value.

Is Rack::Utils::Context compatible.

Not included by default; you must require 'rack/session/abstract/id' to use.

Source:

  class ID    DEFAULT_OPTIONS = {      :key =>           'rack.session',      :path =>          '/',      :domain =>        nil,      :expire_after =>  nil,      :secure =>        false,      :httponly =>      true,      :defer =>         false,      :renew =>         false,      :sidbits =>       128,      :cookie_only =>   true,      :secure_random => (::SecureRandom rescue false)    }

I hope this gives you a lead... when you learn more, can you share your results here?

Edit:

The magic trick is to combine options :cookie_only => false with :defer => true. Of course, the standard Rack::Session::Cookie doesn't make much sense here, so you could do:

use Rack::Session::Pool, :cookie_only => false, :defer => true

Interestingly you can alter the options in run time. In my use case, I actually need to support a traditional cookie-based mechanism alongside the explicit parameter-passing style, so I have done the following:

class WebApp < Sinatra::Base  configure do    use Rack::Session::Pool, :key => 'session_id'  end  before do    # Switch to parameter based session management if the client is an ios device    if env['HTTP_USER_AGENT'] =~ /iOS/      session.options[:cookie_only] = false      session.options[:defer] = true    end  end  get '/' do    session[:user_id] ||= nil # This triggers a session-write, giving us a valid session-id    body "session_id=#{session.id}"  endend


If you want to eliminate usage of cookies in your API application, but still want to manage sessions. For instance, in my case session identifier came from token.You need to redefine method extract_session_id to extract you session identifier from received token. This method have to be redefined on your session store class, because Rack::Session::Abstract::ID provides default implementation, based on cookies.It is called from Rack::Session::Abstract::ID#current_session_id method which calls #id method on session object, usually represented by Rack::Session::Abstract::SessionHash instance. And inside this SessionHash#id method #extract_session_id from your session store finally called.

I suppose it would be simpler to have session identifier extractor configured independently, but desire to store session identifiers in cookies along with session data lead to that tricked design.

As well it is a bit weird to see cookie interaction in Rack::Session::Abstract::ID class in method #commit_session and #set_cookie.So to be completely sure that no cookie will be set you could redefine #set_cookie method on your store as well. The same goal probably can be achived by setting cookie_only: false, defer: true for your session storage middleware, as mentioned in one of the answer here, but I have not checked this.

Definitely you need to modify your middleware stack to exclude all middlewares which interact with cookies and likely browser specific. On default middleware stack of rails it can be look like this:

# config/application.rb[  Rack::MethodOverride, # browser specific  ActionDispatch::Cookies,  ActionDispatch::Flash].each do |middleware|  config.middleware.delete(middleware)end

As well you definitely need to replace session store to something which store information on server side, like redis, for example:

# config/initializers/session_store.rbRails.application.config.session_store ::Custom::Session::TokenRedisStore

In my case, ::Custom::Session::TokenRedisStore inherits ::RedisSessionStore and redefined all methods mentioned above.::RedisSessionStore contained in redis-session-store gem. So, obviously you need to add it to you Gemfile if you going to use it.

I do that for Rails 4.2.x, but same approach can be adopbed to any framework as Rack everywhere the same.