graphql-starter-kit icon indicating copy to clipboard operation
graphql-starter-kit copied to clipboard

Add the flexibility of multiple roles

Open njhargis opened this issue 2 years ago • 1 comments

I have code that creates roles, and users can have multiple roles. It also checks if they have the administrator role, rather than using a flag on the user row. If this is useful to add to the template, let me know and I can add it through a PR.

njhargis avatar Aug 12 '22 22:08 njhargis

@njhargis sounds good! You're very wellcome to fork the repo, create a branch for the roles implementation, and a PR.

If the roles implementation will end-up simple enough, yet generic and flexible, we may decide to merge it into the main branch, alternatively we can leave it as an example branch.

A few things to note:

  • Some developers prefer enforcing permissions using Postgres's row level security policies, while others prefer having security checks at the application level alongside the rest of the (TypeScript) code.
  • It can be convinient to have short keys for the roles, e.g. admin (short key) + Administrator (full name)
  • Some developers would prefer including roles into the authentication (JWT) token, while others would rather not
  • How easy it would be to migrate the app to use the new roles if there are any changes; e.g. it might be a good idea to have the list of roles in the code, so that when you deploy a new version, the list of roles would be automatically updated with the rest of the app (as opposed to allow users tweaking the list of roles in the database).
  • How the authentication code would look like?

For example, if the list of roles will be included into the authentication (JWT) token, it may look like this:

{
  "iss": "https://examle.com",
  "aud": "https://example.com",
  "sub": "123456",
  "exp": 1499863217,
  "roles": ["owner"]
}

If authentication is implemented at the application level, it may look something like this:

async resolve(self, args, ctx) {
  if (!ctx.user) {
    throw new Unuthorized();
  }
  
  if (!ctx.user?.roles.some(role => "editor")) {
    throw new Forbidden();
  }
  
  ...
}

The list of roles may look something like this:

export const userRoles = [
  { role: "owner", name: "Owner" },
  { role: "editor", name: "Editor" },
  { role: "collaborator", name: "External Collaborator" }
];
  • Roles, may contain the list of permission sets.
  • For more complex apps, it should also be possible to group roles.

Further reading

  • https://firebase.google.com/docs/firestore/solutions/role-based-access

koistya avatar Aug 13 '22 14:08 koistya