RobertoSchneiders
Unable to get the URI for a LiveView on_mount authorization hook
I’m trying to get a centralized authentication/authorization system working by using the LiveView on_mount hook, not the handle_params.
This app has pages with different levels of authorization:
- public: can be accessed by anyone, no need to be authenticated
- require authentication: need authenticated users
- require a specific user role: only users with specific roles can access (i.e :admin)
The users can live navigate through those pages, so an unauthenticated user may be able to click a button that navigates to a live view where authentication is required. So the objectives are pretty simple:
- If an unauthenticated user is trying to (live) navigate to a LiveView that requires authentication, we redirect to login.
- after logging in the user is redirected back to the page he wanted to access in the first place (important bit).
- if the user is authenticated but not authorized, we just redirect to home and show a flash message.
I have a module that handles the app authorization based on the URI:
MyApp.authorized(user, uri)
My router:
live_session :default,
on_mount: [
{MyAppWeb.UserAuth, :mount_current_user},
{MyAppWeb.UserAuth, :ensure_authorized}
] do
...
How do I get or build the URI in the on_mount stage? I saw several forum posts and GitHub issues talking about using the handle_params instead. However, that creates several issues in my existing live views because the LiveViews on_mount are executing before authentication/authorization is done. Ideally, I would like to only run the LiveView code once authorization is done. I saw we use to have a few routing helpers (live_path) that would allow me to create the URI based on the live view module (socket.view) and params but that doesn’t exist anymore.
def on_mount(:ensure_authorized, _params, _session, socket) do
uri = "" # <- how to get or build the URI at this stage???
%{assigns: %{current_user: current_user}} = socket
case Authorization.authorized(current_user, uri) do
true ->
socket
|> Phoenix.Component.assign(:live_url, uri)
|> cont()
{:error, :not_authorized} ->
socket
|> Phoenix.LiveView.put_flash(:error, "Not Authorized")
|> Phoenix.LiveView.redirect(to: ~p"/")
|> halt()
{:error, :requires_login} ->
socket
|> Phoenix.LiveView.put_flash(:error, "You must log in to access this page.")
|> Phoenix.LiveView.redirect(to: ~p"/users/log_in?#{%{return_to: uri}}")
|> halt()
end
end
First Post!
krasenyp
I’m not sure your idea would work because when you live navigate, the LiveView you’re navigating to doesn’t get mounted, only handle_params gets run.
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance









