README.md

# Raxx.Session

**Manage HTTP cookies and storage for persistent client sessions.**

[![Hex pm](http://img.shields.io/hexpm/v/raxx_session.svg?style=flat)](https://hex.pm/packages/raxx_session)
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENSE)

- [Install from hex.pm](https://hex.pm/packages/raxx_session)
- [Documentation available on hexdoc](https://hexdocs.pm/raxx_session)
- [Discuss on slack](https://elixir-lang.slack.com/messages/C56H3TBH8/)

### Extract, Embed, Expire a session

```elixir
defmodule MyApp.Action do
  use Raxx.SimpleServer
  alias Raxx.Session

  def handle_request(request, state) do
    {:ok, session} = Session.extract(request, state.session_config)
    updated_session = # ... processing

    response(:ok)
    |> Session.embed(updated_session, state.session_config)

    # ... something went wrong
    response(:forbidden)
    |> Session.expire(state.session_config)
  end
end
```

Sessions are extract and embedded in their entirety from requests/responses.
A session is just a map where any term can be saved,
although large terms might not work with certain session stores.

**If a session is updated it MUST be embedded in the response,
otherwise the client will send the same previous session.**

### Flash

*Flash protection used the `:_flash` key in a session,
it should not be manipulated directly*

A flash is information that should be shown to a user only once.
`Raxx.Session` provides some simple helpers to working with flashes.

```elixir
defmodule MyApp.Action do
  use Raxx.SimpleServer
  alias Raxx.Session

  def handle_request(%{path: ["set-flash"]}, state) do
    session = %{}
      |> Session.put_flash(:info, "Welcome to flash!")
      |> Session.put_flash(:error, "Welcome to flash!")
    redirect("/show-flash")
    |> Session.embed(session, state.session_config)
  end

  def handle_request(request = %{path: ["show-flash"]}, state) do
    {:ok, session} = Session.extract(request, state.session_config)

    {flashes, session} = Session.pop_flash(session)

    response(:ok)
    |> render(flashes)
    |> Session.embed(session, state.session_config)
  end
end
```

### CSRF Protection

*CSRF protection used the `:_csrf_token` key in a session,
it should not be manipulated directly*

`Raxx.Session.extract/2` is protected against CSRF attacks.
Sessions can be extracted from safe requests.
These are `GET`, `HEAD` or `OPTIONS` requests and they should have no side effect.

Requests with other methods must provide a `csrf_token`.
By default this value is looked for in the `x-csrf-token` header.

If the token is sent to the server in a different manner it can be explicitly passed by using `Raxx.Session.extract/3`.
For example if it is passed in the body of a request

```elixir
{%{"_csrf_token" => token}} = URI.decode(request.body)

{:ok, session} = Raxx.Session.fetch(request, token, config)
```

**A CSRF token should not be sent back to the server as a query parameter.**

### Configuration

```elixir
session_config = Raxx.Session.config(
                    key: "my_session",
                    store: Raxx.Session.SignedCookie,
                    secret_key_base: String.duplicate("squirrel", 8),
                    salt: "epsom"
                  )
```

For all configuration options see `Raxx.Session` or specific stores.

#### Plug sessions

Sessions from Plug applications can be verified in Raxx applications, and visa versa,
if setup with the same configuration.