DEV Community

Cover image for Elixir Überauth: how to keep state between request and callback?
Federico Meini
Federico Meini

Posted on

Elixir Überauth: how to keep state between request and callback?

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

The team behind the library has recently improved its security against CSRF attacks. Unfortunately, the security improvement comes at a cost for the end user, as it is now impossible to keep state between the request and callback phases of the OAuth process.

Background

Most OAuth providers (e.g. Google) allow developers to pass custom state inside a state query parameter as part od the request URL. The OAuth provider then passes the state back when calling our callback endpoint.

Überauth now uses the state query parameter to pass the 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 a session cookie in the request phase and retrieve it from the session in the callback phase.

Code example

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

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 session
    auth_custom_state = get_session(conn, :auth_custom_state)

    IO.inspect(auth_custom_state, label: "Auth custom state")
  end
end
Enter fullscreen mode Exit fullscreen mode

With that code, I am able to 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 take it back from the session in the callback function.

Top comments (0)