Setting the return_to for ash authentication

Bet wishes to everyone, especially to the ash core team members for creating such an amazing framework.

I have a question regarding ash_authentication. I added ash_authentication to my application and so far it is working splendid. The issue I have that is after I sign in the user does not get redirected to the page they were trying to go to. I did some debugging and I noticed that the return_to value in the session of the Authentication Controller is always nil thus the application defaults to the “/” route.

So the question is how can I set this variable so the user gets returned to the page they were trying to log in to.

Kind regards,

1 Like

I believe this is something that you’ll want to set yourself when you redirect the user to a route to log in. @jimsynz may be able to add some more context. Essentially somewhere in your app, either in a plug or in an on_mount hook (or both) is a thing that will redirect users to the log in page if they aren’t logged in. In that redirect, you’d want to set the return_to parameter to the url they were trying to access.

Thanks for the pointer, I will need to see a bit how I will approach this.

I added the following plug to my application.

For anyone willing to use this, a few pointers. The log statements are very useful for debugging and understanding whats going on in your app but they will slow down your app because they happen on every request. So remove them for serious use.

The @invalid_return_to is added so the return_to variable does not get overwritten during your authentication process. The exact values depend on the authentication system you are using. So you might need to change them to work with your app.

defmodule MyAppWeb.ReturnToPlug do
  import Plug.Conn

  @invalid_return_to ["auth", "sign-in", "sign-out"]

  def init(default), do: default

  def call(conn, _default) do
    IO.puts("""
    Verb: #{inspect(conn.method)}
    Host: #{inspect(conn.query_string)}
    Headers: #{inspect(conn.request_path)}
    session: #{inspect(get_session(conn))}
    """)

    conn.request_path
    |> is_invalid_return_to()
    |> if do
      conn
    else
      put_session(conn, :return_to, add_query_parameter(conn.request_path, conn.query_string))
    end
  end

  defp is_invalid_return_to(path) do
    @invalid_return_to
    |> Enum.map(fn invalid -> String.contains?(path, invalid) end)
    |> Enum.any?()
  end

  defp add_query_parameter(path, query) do
    if query == "" do
      path
    else
      "#{path}?#{query}"
    end
  end
end

And in the router add:

    plug MyAppWeb.ReturnToPlug
2 Likes

This is neat :slight_smile: Maybe we should add something like this to ash_authentication at some point.

You are welcome to use it, ;). I did not do a lot of testing yet so there might be a few bugs hiding.

I did a bit more testing and I noticed that when i signed out it keeps returning me to the login screen. This is because the auth_controller of AshAuthenticationPhoenix also makes use of the return_to value. In my case I just want it to return me to my homepage so with a small edit to the controller this was easily solved.

    return_to = g̵e̵t̵_̵s̵e̵s̵s̵i̵o̵n̵(̵c̵o̵n̵n̵,̵ ̵:̵r̵e̵t̵u̵r̵n̵_̵t̵o̵)̵ ̵|̵|̵ ~p"/"

Another solution might be to prevent setting the return_to variable when we have a logged in user.

1 Like