{"title":"Sessions","description":"Use Amber V2 sessions and flash messages safely","section":"guides/controllers","version":"v2","path":"guides/controllers/sessions","canonical_url":"https://amberframework.org/docs/v2/guides/controllers/sessions","markdown_url":"https://amberframework.org/docs/v2/guides/controllers/sessions.md","inherited":false,"content_markdown":"# Sessions\n\nAmber exposes `session` and `flash` directly inside a controller. Amber CLI's\nV2 web template enables the session and flash pipes in this order.\n\n**File: `config/routes.cr` — keep this order inside the generated `pipeline\n:web` block.**\n\n```crystal\npipeline :web do\n  plug Amber::Pipe::Error.new\n  plug Amber::Pipe::Logger.new\n  plug Amber::Pipe::Session.new\n  plug Amber::Pipe::Flash.new\n  plug Amber::Pipe::CSRF.new\nend\n```\n\nKeep `Session` before `Flash`: flash messages are serialized through the\nsession after the request.\n\n## Generated configuration\n\nThe web template writes the following section to each environment YAML file.\n\n**Files: `config/environments/development.yml`,\n`config/environments/test.yml`, and `config/environments/production.yml` — edit\nthe existing `session:` section in each environment rather than adding a\nduplicate key.**\n\n```yaml\nsession:\n  key: my_app.session\n  store: signed_cookie\n  adapter: memory\n  expires: 0\n```\n\nThe V2 session store uses the configured adapter for session values and an\nencrypted cookie for the session identifier. The built-in `memory` adapter is\nuseful for local development and tests, but its data is process-local. Choose a\nshared custom adapter before running multiple application processes or before\ndepending on sessions that must survive a restart. See [Session\nAdapters](../adapters/sessions.md).\n\nProduction also requires a long `AMBER_SERVER_SECRET_KEY_BASE`; Amber uses it\nto protect cookies. Do not commit a production secret to the YAML file.\n\n## Read, write, and delete values\n\nSession keys accept strings or symbols. Values are stored as strings.\n\n**File: `src/controllers/logins_controller.cr` — place these actions inside\n`LoginsController`, then register their routes in `config/routes.cr`.**\n\n```crystal\nclass LoginsController < ApplicationController\n  def create\n    # Replace this lookup with your application's authentication logic.\n    user_id = \"42\"\n    session[:current_user_id] = user_id\n\n    # Regenerate an adapter-backed session ID after authentication to prevent\n    # session fixation. This is a no-op for a cookie-only store.\n    context.regenerate_session!\n\n    flash.notice = \"Welcome back.\"\n    redirect_to location: \"/\", status: 302\n  end\n\n  def destroy\n    session.delete(:current_user_id)\n    flash[:notice] = \"You have signed out.\"\n    redirect_to location: \"/\", status: 302\n  end\nend\n```\n\n**File: the controller action that needs the authenticated identity — use the\noptional lookup where absence is expected.**\n\n```crystal\nif user_id = session[:current_user_id]?\n  # Load the user through the persistence layer selected by the application.\nend\n```\n\nKeep session payloads small and non-sensitive. Store a stable identifier, not\nan entire model or authorization policy, and verify authorization again on\nevery protected request.\n\n## Flash messages\n\nFlash values are intended for the next request. Reading a value marks it for\nremoval; `keep` carries it forward, while `now` makes a value available only in\nthe current request.\n\n**File: the controller action that sets the message.**\n\n```crystal\nflash[:error] = \"Please correct the highlighted fields.\"\nflash.keep(:error)\nflash.now(:notice, \"The preview was not saved.\")\n```\n\n**File: `src/views/layouts/_flash.ecr` — create this reusable partial, then\nrender it from `src/views/layouts/application.ecr`.**\n\n```ecr\n<% flash.each do |name, message| %>\n  <div class=\"flash flash-<%= name %>\"><%= message %></div>\n<% end %>\n```\n\n**File: `src/views/layouts/application.ecr` — add this call where global\nmessages should appear.**\n\n```ecr\n<%= render(partial: \"layouts/_flash.ecr\") %>\n```\n\nThe V1 guide's inline Redis configuration is not a V2 configuration contract.\nImplement and register a session adapter instead, then select it with the\n`session.adapter` setting."}