{"title":"Sessions","description":"","section":"guides/controllers","version":"v1.5","path":"guides/controllers/sessions","canonical_url":"https://amberframework.org/docs/v1.5/guides/controllers/sessions","markdown_url":"https://amberframework.org/docs/v1.5/guides/controllers/sessions.md","inherited":true,"content_markdown":"# Sessions\n\n## The Session\n\nAmber uses an Amber:Router::Session::Store to manage session storage. This store is most suitable when your sessions don't hold critical data and don't need to persist for long periods.\n\nThe default session store in Amber relies on cookies, offering significantly faster performance compared to other options. It automatically configures the cookie store based on your application's settings.\n\nSessions typically carry minimal data, such as a user\\_id and flash message, fitting within the 4K cookie size limit. If you attempt to store more than 4K of data, it triggers a CookieOverflow exception.\n\nTo configure the session:\n\n```crystal\n#  Cookie Store\nAmber.settings.session = {\n  :key     => \"name.session\",\n  :store   => \"cookie\",\n  :expires => 120, \n  # :expires => 0,\n  # would make the session last as long as the browser is open;\n  # upon closing the browser, the session would terminate.\n  :secret  => \"secret\"\n}\n\n# Redis Store\nAmber.settings.session = {\n  :key       => \"name.session\",\n  :store     => \"redis\",\n  :expires   => 120,\n  :secret    => \"secret\",\n  :redis_url => \"redis://localhost:6379\",\n}\n```\n\nAlso, include the Session into the Pipeline:\n\n```crystal\n# Keep in mind the order of the Pipes. Session hash needs to be populated before \n# trying to access the session flash scope, the flash depends on the session. \npipeline :web do\n  plug Amber::Pipe::Session.new\n  plug Amber::Pipe::Logger.new\n  plug Amber::Pipe::Flash.new\n  plug Amber::Pipe::CSRF.new\nend\n```\n\nTo access the session:\n\n```crystal\nclass ApplicationController < Amber::Controller::Base\n  # Finds the User with the ID stored in the session with the key\n  # :current_user_id This is a common way to handle user login in\n  # an Amber application; logging in sets the session value and\n  # logging out removes it.\n  private def current_user\n    @_current_user ||= session[:current_user_id] &&\n      User.find_by(id: session[:current_user_id])\n  end\nend\n```\n\nTo store something in the session, just assign it to the key like a hash:\n\n```crystal\nclass LoginsController < ApplicationController\n  # \"Create\" a login, aka \"log the user in\"\n  def create\n    if user = User.authenticate(params[:username], params[:password])\n      # Save the user ID in the session so it can be used in\n      # subsequent requests\n      session[:current_user_id] = user.id\n      redirect_to root_url\n    end\n  end\nend\n```\n\nTo remove something from the session, use `session.delete(key)`:\n\n```crystal\nclass LoginsController < ApplicationController\n  # \"Delete\" a login, aka \"log the user out\"\n  def destroy\n    # Remove the user id from the session\n    @_current_user = nil\n    session.delete(:current_user_id)\n    redirect_to root_url\n  end\nend\n```\n\n### The Flash\n\nThe flash is a special part of the session that resets after each request. This means any stored values are only available for the next request. It's handy for passing error messages or similar information.\n\nTo access the flash, you treat it like a hash, much like accessing the session itself.\n\nLet's take logging out as an example. The controller can send a message that will be shown to the user on their next request:\n\n```crystal\nclass LoginsController < ApplicationController\n  def destroy\n    session[:current_user_id] = nil\n    #  Alternatively, `flash.notice=` could be use.\n    flash[:notice] = \"You have successfully logged out.\"\n    redirect_to root_url\n  end\nend\n```\n\nRendering the flash message:\n\n```markup\n<html>\n  <!-- <head/> -->\n  <body>\n    <% flash.each do |name, msg| -%>\n      <%= content_tag :div, msg, class: name %>\n    <% end -%>\n\n    <!-- more content -->\n  </body>\n</html>\n```\n\nIf you want a flash value to be carried over to another request, use the keep method:\n\n```crystal\nclass MainController < ApplicationController\n  # Let's say this action corresponds to root_url, but you want\n  # all requests here to be redirected to UsersController#index.\n  # If an action sets the flash and redirects here, the values\n  # would normally be lost when another redirect happens, but you\n  # can use 'keep' to make it persist for another request.\n  def index\n    # Will persist all flash values.\n    flash.keep\n\n    # You can also use a key to keep only some kind of value.\n    # flash.keep(:notice)\n    redirect_to users_url\n  end\nend\n```\n\n#### Flash.now\n\nBy default, adding values to the flash will make them available to the next request, but sometimes you may want to access those values in the same request. For example, if the create action fails to save a resource and you render the new template directly, that's not going to result in a new request, but you may still want to display a message using the flash. To do this, you can use flash.now in the same way you use the normal flash.\n\n```crystal\nclass ClientsController < ApplicationController\n  def create\n    client = Client.new(params[:client])\n    if client.save\n      # ...\n    else\n      flash.now[:error] = \"Could not save client\"\n      render action: \"new\"\n    end\n  end\nend\n```\n\nMake sure the Flash, Session and CSRF pipelines are enabled in your `routes.cr` file and in the order that the scaffolding renders them.\n\n## CSRF\n\nTo use CSRF, enable the pipe in your `routes.cr`\n\nThen, insert the `csrf_tag` helper in your forms.\n\n### How to use CSRF with Ajax\n\nTo use CSRF with Ajax, simply call the `csrf_tag` helper inside your controller and return it as part of a JSON object:\n\n```crystal\ndef my_action\n    {csrf: csrf_tag}.to_json\nend\n```\n\nIn your Javascript, after getting the JSON object back, refresh your CSRF tag with the one from the server.\n\n```javascript\n$(\"input[name*=_csrf]\").replaceWith(e['csrf']);\n```"}