---
title: "Keeping custom state across the Überauth OAuth flow in Elixir"
description: "Überauth now uses the OAuth state parameter for CSRF protection, so custom state gets overwritten. Keep it in the session between request and callback instead."
author: Federico Meini
date: 2021-08-12
tags: [elixir, ueberauth, oauth, authentication]
language: en
url: https://fedme.dev/blog/2021_08_12_ueberauth_state
---

# Keeping custom state across the Überauth OAuth flow in Elixir

Überauth is probably the go-to OAuth login library for Elixir projects.

The team behind the library recently improved its protection against CSRF attacks. Unfortunately, the improvement comes at a cost for developers: it is no longer possible to keep custom state between the request and callback phases of the OAuth flow using the `state` parameter.

## Background

Most OAuth providers (Google, for example) let developers pass custom state in a `state` query parameter as part of the request URL. The provider then passes that state back when it calls our callback endpoint.

Überauth now uses the `state` query parameter to carry its CSRF token, overwriting whatever custom state developers put in the request URL.

## Workaround

Luckily, there is another way. We can put our custom state in the session cookie during the request phase and read it back from the session in the callback phase.

### Code example

The following snippet shows how to save some custom state in the session and retrieve it in the callback phase of the OAuth flow:

```elixir
defmodule MyAppWeb.AuthController do
  use MyAppWeb, :controller

  plug(Ueberauth, providers: [:google_custom])

  @provider_config {Ueberauth.Strategy.Google, [default_scope: "email profile"]}

  def request(conn, %{"provider" => "google", "custom_state" => custom_state}) do
    # Store custom state in the session
    conn
    |> put_session(:auth_custom_state, custom_state)
    |> Ueberauth.run_request("google", @provider_config)
  end

  def callback(conn, _params) do
    %{assigns: %{ueberauth_auth: auth}} =
      conn
      |> Ueberauth.run_callback("google", @provider_config)

    # Get custom state back from the session
    auth_custom_state = get_session(conn, :auth_custom_state)
    IO.inspect(auth_custom_state, label: "Auth custom state")
  end
end
```

With that code, I can start the OAuth flow passing some custom state in the URL (e.g. `https://localhost:4000/auth/google?custom_state=some_values_here`) and then get it back from the session in the `callback` function.
