1

I have two users, Buyer and Admin in my app, they both have different login details, admin logs in with email and password, buyer logs in with their phone number and a code we send them. So, I made two authentication plugs. Here is how I have added the plugs to my browser pipeline:

pipeline :browser do
  plug :accepts, ["html"]
  plug :fetch_session
  plug :fetch_flash
  plug Phoenix.LiveView.Flash
  plug :protect_from_forgery
  plug :put_secure_browser_headers
  plug AffirmWeb.BuyerAuth
  plug AffirmWeb.AdminAuth
end

So here is the problem, when the admin logs in, they get the login menu and they can access all the other pages. When the buyer logs in, I can see from the logs(I IO.inspect the conn so I know they are logged in), they still get the "signed out" menu, they also cannot access some pages. If I change the piping order to have AffirmWeb.BuyerAuth comes last, now the buyer can access other pages and admin cannot. Any guidance on how I can go about this?

Adam Millerchip
  • 20,844
  • 5
  • 51
  • 74
Linda Kadz
  • 329
  • 2
  • 17
  • 1
    Do your authentication plugs do their own redirect? It's possible the first plug redirects to the "signed out" menu before your conn gets to the second plug. You'll want to change your plugs to either 1) mark your conn as authenticated or not and have a third plug do the redirect; or 2) combine your plugs into a single authentication plug (assuming both need the same routes) – Brett Beatty Mar 31 '20 at 02:02
  • So both redirect to the same route after authenticating. Just trying to see how I can join them as one plug at the moment. – Linda Kadz Mar 31 '20 at 02:17

2 Answers2

2

Why not use scoped routes and create two pipelines and two scopes, one for the buyers and one for the admins:

pipeline :browser do
  plug :accepts, ["html"]
  plug :fetch_session
  plug :fetch_flash
  plug Phoenix.LiveView.Flash
  plug :protect_from_forgery
  plug :put_secure_browser_headers
end

pipeline :buyer do
  plug AffirmWeb.BuyerAuth
end

pipeline :admin do
  plug AffirmWeb.AdminAuth
end

scope "/" do
  pipe_through :browser

  # ...routes for unauthenticated visitors...
end

scope "/buyer", AffirmWeb.Buyer do
  pipe_through [:browser, :buyer]

  # ...buyer routes...
end

scope "/admin", AffirmWeb.Admin, as: :admin do
  pipe_through [:browser, :admin]

  # ...admin routes...
end

Now it is much easier to differentiate between user types and use different plugs, controllers or layout templates.

You can play with the options for scope to get different results for the produced urls and path helpers.

zwippie
  • 15,050
  • 3
  • 39
  • 54
0

It’s extremely hard to suggest anything without seeing the real code of auth plugs, but the general advice would be: compose a single plug out of two and do logical or there. In your current code, the latter seems to always win which might be roughly described with the following pseudocode:

a = is_buyer?
a = is_admin?
return a

Instead, you want somewhat like

a = 
  cond do
    is_buyer? -> :buyer
    is_admin? -> :admin
    _ -> :unknown
  end

So, create a plug that would be calling your existing plugs and return as soon as any condition is met.

Aleksei Matiushkin
  • 119,336
  • 10
  • 100
  • 160