Deleting the Current Session with Rack::Session::Cookie

Deleting the current session with Rack::Session::Cookie

Just use

session.clear

to destroy the session.

Rack.session cookie not being deleted even after /logout code runs in Sinatra

session.clear will remove the session vars. You'll still see a session in chrome because it is set by Rack::Session::Cookie middleware after your action has run, but that is just a blank session.

Sinatra/1.4.3 use Rack::Session::Cookie warning

You are using both

enable :sessions

which makes Sinatra setup cookie based sessions, and

use Rack::Session::Cookie, ...

which also adds sessions to your app, so you end up with two instances of Rack::Session::Cookie in your middleware stack.

The warning is being generated by the session middleware included by Sinatra. By default Sinatra doesn’t create a session secret when running in the development environment (in classic mode at least, it does for modular apps), and so Rack generates the warning in development.

You should only need one of the two ways of enabling sessions, using two together could result in them interacting in unexpected ways.

To avoid the warning, you can explicitly set a secret for the Sinatra session with the session_secret option:

enable :sessions
set :session_secret, '*&(^B234'

You can also pass the options hash as an argument when enabling sessions. Instead of enable :sessions, do this:

set :sessions, key: 'N&wedhSDF',
domain: "localhost",
path: '/',
expire_after: 14400,
secret: '*&(^B234'

Rack: Multiple session cookies for a single rack application

In case anyone run with the same needs, I found that making a class to managing sessions inside the application was the easiest way to go.

Rack::Utils have 2 nice shortcuts, Rack::Utils.set_cookie_header! and Utils.delete_cookie_header! that can really make the things easier when dealing with cookies.

I am saving the sessions in the database used my application, but it should be trivial to support another back-end.

As a side note, a few considerations I came with:

  • To be sure to the name of the cookie is valid, I am using a sha-1 of the sub-application name for that purpose.
  • SecureRandom.urlsafe_base64 is useful for generating session key.
  • Sessions cleaning and refreshing has to be implemented manually.

Sample code

The class managing the cookies, the commit function set and delete the cookies to rack.

class Framework::Response::Cookies

def set( params )
@cookies[params.delete( :name )] = params
end

def remove( params )
@remove_cookies[params.delete( :name )] = params
end

def commit( headers )
@cookies.each_pair do |name, params|
Rack::Utils.set_cookie_header!( headers, name, params )
end
@remove_cookies.each_pair do |name, params|
Rack::Utils.delete_cookie_header!( headers, name, params )
end
end

end

The class managing the session (using Mongo as a backend):

class Database::Mongo::Session < Session

def save
expire = Time.now + @session_ttl
@framework.content.db.find_and_modify( self.collection_name, {
:query => { :name => @session_name, :id => @session_id },
:update => { :expire => expire, :name => @session_name, :id => @new_session_id || @session_id , :variables => @variables.to_hash },
:upsert => true
})
@framework.response.cookies.set(
:name => @session_name,
:value => @new_session_id || @session_id,
:path => @framework.applications.active.active_request['path'],
:domain => @framework.applications.active.active_request['host'],
:httponly => true
)
end

def delete
@framework.content.db.remove( self.collection_name, { :id => @session_id } )
@framework.response.cookies.remove( :name => @session_name )
end

end

Each time @framework.response.cookies.set is called, it pushes a cookie data to the Framework::Response::Cookies class @cookies variable.

Before serving the response, a call to Framework::Response::Cookies.commit commit the cookies using Rack::Utils.

Sinatra clears session on post

I was suffering from the same issue as you: sessions were being cleared on post.

I have no idea why this works, but this is my solution:

#enable :sessions
use Rack::Session::Cookie, :key => 'rack.session',
:path => '/',
:secret => 'your_secret'

I literally just replaced the enable :sessions bit with use Rack::Session::Cookie ... and now all is good in the world.

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 sessioning
service. Cookies sent to the client for maintaining sessions will only
contain an id reference. Only #get_session and #set_session are
required 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 related
    cookie 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 session
    state if it is used with a backend
  • :renew (implementation dependent) will prompt the generation of a new
    session 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 session
    id will be.

These options can be set on a per request basis, at the location of
env['rack.session.options']. Additionally the id of the session can be
found within the options hash at the key :id. It is highly not
recommended 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}"
end
end

Set Rack session cookie expiration programmatically

I was trying to do the exact same thing and I figured out what the problem for me was. The session cookie gets set on every request if you have an expire_after time set. So when you say if (!remember_me), for that request the cookie's expire time gets set to nil. However, on the very next request, the session cookie is reinitialized with an expire time of 2592000. It seems the fix is to not set a default expire_after time and instead say:

# don't set default expire time
use Rack::Session::Cookie, :secret => MY_SECRET

if(remember_me)
env['rack.session.options'][:expire_after] = 2592000
end

I have unfortunately not figured out how to have a default expire_after time and to permanently extend that time programatically.



Related Topics



Leave a reply



Submit