Authentication and Roles - every user have a role, or only if a special user?

I have been building a user authentication system with user roles. I am now at a point where I am starting to really dig into routing based on roles and I am running into problems. I have built it with the idea that a role is required. I am now finding that this has some pitfalls and I want to know if I should have done it another way. What are the benefits to have every user have a role compared to only having a role if needed otherwise assume not special user?

2 Likes

In my understanding users are dispatched by roles. So there would be for example admins, superadmins and default users. For the last ones, the role could be called client, member, or even user or default. There should not be many roles, or at least not much more than there are user interfaces. This way the routing will be easier I think.

For example we can things like:

  # somewhere in a router to allow only `admins` and `superadmins`
  pipeline :admin do
    plug :browser
    plug :ensure_role, [:admin, :superadmin]
  end
# Then in some Controller
plug(:ensure_role, :superadmin when action in [:delete])

If for example superadmins had their own UI, and so for for admins, it would be even more straightforward to do the routing,

For routes allowed to all authenticated user, I just use some plug like require_user, for ones that need not to be authenticated I have require_guest.

One issue I encountered was when I tried to assign multiple roles to the same user. That will complicate things a lot. So I try to avoid that and create roles that fully qualified users.

I’m a Phoenix/Elixir noob, but I did a PHP app using Role Based Access Control (https://auth0.com/docs/authorization/concepts/rbac), in which every user has one or more roles, and every role has one or more permissions. Each permission usually would map to a route. Hopefully that helps.

When i can do the job without permissions’ complexity, I really prefer that. But It’s certain that for some kind of requirements, just roles won’t be sufficient to handle authorization. I guess what I call “role” should rather be called “user type”?

You can define two pipelines, one requiring the user to be authenticated (with role), the other without such requirement.

  pipeline :api do
    plug(:accepts, ["json"])
  end

  pipeline :jwt_authenticated do
    plug(Guardian.AuthPipeline)
  end

  scope "/api", AtmWeb do

    pipe_through(:api)

    post("/sign_up", UserController, :create)
    post("/sign_in", UserController, :sign_in)
    resources("/categories", CategoryController, except: [:new, :edit]) # no role required
    ...
end

  scope "/api", AtmWeb do
    pipe_through([:api, :jwt_authenticated])
   
    resources("/records", RecordController, except: [:new, :edit]) # role is needed and verified by controller.
    ...
end