Admin + Organization Plugin: Role Columns

I have a question about using the admin and organization plugins together. When using the admin plugin, it adds a role column to the user table and when using the organization plugin, it creates a member table that itself contains a role column along with a userId column that references the earlier user table. The question I have is, how should the relationship between those two distinct role columns be managed? What are the expectations?
31 Replies
Netrifier
Netrifier5d ago
The admin and organisation roles are separate from each other. And as you mentioned, the admin roles are in the user schema and the organisation roles are in the member schema. Which means that admin roles are for the entire app while the organisation roles are scoped to that particular organisation means you can have diff roles for diff organisations while having certain other roles for the entire app.
MaveriX89
MaveriX89OP5d ago
Oh, interesting -- so the distinction is to think of the User level role column as an app-wide role regardless of organization?
Netrifier
Netrifier5d ago
yes, currently there can be only one role in the user but organisation members can have multiple roles
MaveriX89
MaveriX89OP5d ago
That's interesting.... On that note of multiple roles though -- when calling addMember like so:
await auth.api.addMember({
body: {
organizationId: <org_id>,
userId: <user_id>,
role: "owner", // this only accepts a single, strongly typed string
},
});
await auth.api.addMember({
body: {
organizationId: <org_id>,
userId: <user_id>,
role: "owner", // this only accepts a single, strongly typed string
},
});
I can't pass an array or a comma delimited string to the addMember call
Netrifier
Netrifier5d ago
yes you have to separate the roles with a comma https://www.better-auth.com/docs/plugins/organization#access-control
Organization | Better Auth
The organization plugin allows you to manage your organization's members and teams.
MaveriX89
MaveriX89OP5d ago
Right, what I'm saying is, the method does not accept it -- it complains Or, more precisley, TypeScript complains about it -- so should that TS complaint be ignored?
Netrifier
Netrifier5d ago
means you are saying that the role is type checked with the provided roles? this might be a bug will do some searching in the source code
MaveriX89
MaveriX89OP5d ago
Exactly It's type-checked to match to the enumerated role-set you defined and does not accept an array or comma-delimited string value
Netrifier
Netrifier5d ago
the roles are correctly split with a "," so might be a typescript thing
No description
Netrifier
Netrifier5d ago
can you do some tests with ignoring the typescript errors I will check if the types can be updated
MaveriX89
MaveriX89OP5d ago
Yeah, considering there is strict type-saftey in inferring the types through the config, I wonder if it might be better served to type the role value of that API call to be something like RoleSetValue[] instead of RoleSetValue or string string would obviously allow for comma-delimited entry but won't be able to guarantee the values that the user enters will match the defined set of role values Let me give it a test
Netrifier
Netrifier5d ago
I was wondering the same thing
MaveriX89
MaveriX89OP5d ago
This is what I see in my DB after running it with comma-delimited values (despite TS complaining) which I believe is the expected outcome
No description
MaveriX89
MaveriX89OP5d ago
(This is all randomly generated fake data btw 😂 )
Netrifier
Netrifier5d ago
👍
Netrifier
Netrifier5d ago
this is the current role type
No description
Netrifier
Netrifier5d ago
this only supports single strings which are already defined
MaveriX89
MaveriX89OP5d ago
Yeah, so the suspicion was correct then 👍 Just need to type that sucker to be an array of those values instead 🙂 Or perhaps both? a single typed string or an array of them? That way you have backwards compatibility and it won't be a breaking API change
Netrifier
Netrifier5d ago
I believe achieving a typed string would be a bit complex but I agree that the roles should be switched to using an array type
MaveriX89
MaveriX89OP5d ago
Oh, I was thinking it would be a simple transition but I'm probably missing something in the equation. I thought the existing type can just be reused to express something like:
role: ExistingType | ExistingType[];
role: ExistingType | ExistingType[];
Netrifier
Netrifier5d ago
the current type does not support the multiple roles with comma so I was referring to that comma string.
MaveriX89
MaveriX89OP5d ago
Ah, gotcha Yeah, I think supporting that in the API signature would be a headache Perhaps not worth the cost of maintenance if the same outcome can be achieved using a typed array
Netrifier
Netrifier5d ago
the typed array would be great but not all databases support storing arrays so they still need to be stored as string separated with comma but this serialization can be handled in the adapter so this would mean a partial refactoring of the organisation plugin to switch the string to array if the better-auth team give the go ahead I am ready to make a pr
MaveriX89
MaveriX89OP5d ago
Would there be complaints from users for the breaking change on the signature?
Netrifier
Netrifier5d ago
this would definitely be a breaking change if somehow both can be supported then it would be fine I think this would be the better option
MaveriX89
MaveriX89OP5d ago
This is what I'm thinking I think both can be supported since we just need to extend the current signature
Netrifier
Netrifier5d ago
yes, I will do some tests and see, and if the team gives the go ahead I can make a pr
MaveriX89
MaveriX89OP5d ago
The cost of that would be that the addMember method would have to do a check along the lines of:
const parseRoles = (role: TypedRole | TypedRole[]) => {
if (Array.isArray(role)) { /* join roles using comma */ }
else /* role is a string like the existing signature supports */
const parseRoles = (role: TypedRole | TypedRole[]) => {
if (Array.isArray(role)) { /* join roles using comma */ }
else /* role is a string like the existing signature supports */
Netrifier
Netrifier5d ago
this wouldn't be that bad and array.isarray is very fast I was thinking of defining an utility function then calling it wherever roles are needed which will increase maintainability as the logic will be in one place
Netrifier
Netrifier5d ago
https://github.com/better-auth/better-auth/pull/1792 This only changes types for add member and create invitation to stop those typescript errors. These changes do not break backwards compatibility.
GitHub
fix(organization): Fix multiple role array not referenced properly ...
Added support to pass multiple roles to addMember Changed role type to InferRolesFromOption&lt;O&gt; | InferRolesFromOption&lt;O&gt;[] to stop typescript errors when using array wit...
MaveriX89
MaveriX89OP5d ago
Excellent!

Did you find this page helpful?