Typescript doesn't like my new role of "approved"

I've extended the type according to the docs:
import { db } from "@/server/db"; // your drizzle instance
import { betterAuth } from "better-auth";
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { nextCookies } from "better-auth/next-js";
import { admin } from "better-auth/plugins/admin";

export const auth = betterAuth({
emailAndPassword: {
enabled: true,
},
database: drizzleAdapter(db, {
provider: "pg", // or "mysql", "sqlite"
}),
user: {
additionalFields: {
role: {
type: "string",
},
},
},
plugins: [
nextCookies(),
admin({
adminRoles: ["admin"],
}),
],
});
import { db } from "@/server/db"; // your drizzle instance
import { betterAuth } from "better-auth";
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { nextCookies } from "better-auth/next-js";
import { admin } from "better-auth/plugins/admin";

export const auth = betterAuth({
emailAndPassword: {
enabled: true,
},
database: drizzleAdapter(db, {
provider: "pg", // or "mysql", "sqlite"
}),
user: {
additionalFields: {
role: {
type: "string",
},
},
},
plugins: [
nextCookies(),
admin({
adminRoles: ["admin"],
}),
],
});
but on the front-end, when I try to do an update role (using the admin plugin), it only wants to see admin or user. Those are the default roles for admin, so how do I get my new role in there?
Solution:
Am I looking at "roles" wrong? I want people to be able to sign up, whcih gives them the "user" role, but I don't want them to be able to do anything until they get approved by an admin. Currently I am setting a role of "approved" on them (a custom role with the ac stuff). Is that the normal flow? is this the same perms as the userAc?...
Jump to solution
11 Replies
Tyler
TylerOP4mo ago
I did create this and pass it to my betterAuth instance, still have the same error tho:
import { createAccessControl } from "better-auth/plugins/access";
import { defaultStatements, userAc } from "better-auth/plugins/admin/access";

const statement = {
...defaultStatements,
} as const;

const ac = createAccessControl(statement);

export const approvedRole = ac.newRole({
...userAc.statements,
});
import { createAccessControl } from "better-auth/plugins/access";
import { defaultStatements, userAc } from "better-auth/plugins/admin/access";

const statement = {
...defaultStatements,
} as const;

const ac = createAccessControl(statement);

export const approvedRole = ac.newRole({
...userAc.statements,
});
I think I had to pass like this?
export const auth = betterAuth({
emailAndPassword: {
enabled: true,
},
database: drizzleAdapter(db, {
provider: "pg", // or "mysql", "sqlite"
}),
user: {
additionalFields: {
role: {
type: "string",
},
},
},
plugins: [
nextCookies(),
admin({
adminRoles: ["admin"],
roles: {
admin: adminAc,
user: userAc,
approved: approvedRole,
},
}),
],
});
export const auth = betterAuth({
emailAndPassword: {
enabled: true,
},
database: drizzleAdapter(db, {
provider: "pg", // or "mysql", "sqlite"
}),
user: {
additionalFields: {
role: {
type: "string",
},
},
},
plugins: [
nextCookies(),
admin({
adminRoles: ["admin"],
roles: {
admin: adminAc,
user: userAc,
approved: approvedRole,
},
}),
],
});
and in client:
export const authClient = createAuthClient({
/** The base URL of the server (optional if you're using the same domain) */
baseURL: "http://localhost:3000",
plugins: [
adminClient({
roles: {
admin: adminAc,
user: userAc,
approved: approvedRole,
},
}),
inferAdditionalFields<typeof auth>(),
],
});
export const authClient = createAuthClient({
/** The base URL of the server (optional if you're using the same domain) */
baseURL: "http://localhost:3000",
plugins: [
adminClient({
roles: {
admin: adminAc,
user: userAc,
approved: approvedRole,
},
}),
inferAdditionalFields<typeof auth>(),
],
});
Is that correct?
Soheel
Soheel4mo ago
https://www.better-auth.com/docs/plugins/admin#pass-roles-to-the-plugin pretty sure it’s because you forgot to pass the actually updated access control instance to the plugin (the ac object)
Admin | Better Auth
Admin plugin for Better Auth
Solution
Tyler
Tyler4mo ago
Am I looking at "roles" wrong? I want people to be able to sign up, whcih gives them the "user" role, but I don't want them to be able to do anything until they get approved by an admin. Currently I am setting a role of "approved" on them (a custom role with the ac stuff). Is that the normal flow? is this the same perms as the userAc?
import { createAccessControl } from "better-auth/plugins/access";
import { defaultStatements, userAc } from "better-auth/plugins/admin/access";

const statement = {
...defaultStatements,
} as const;

const ac = createAccessControl(statement);

export const approvedRole = ac.newRole({
...userAc.statements,
});
import { createAccessControl } from "better-auth/plugins/access";
import { defaultStatements, userAc } from "better-auth/plugins/admin/access";

const statement = {
...defaultStatements,
} as const;

const ac = createAccessControl(statement);

export const approvedRole = ac.newRole({
...userAc.statements,
});
Soheel
Soheel4mo ago
this approved role now has the same rights as the userRole in that case you should give the user role no statements most likely
Tyler
TylerOP4mo ago
okay but it is correct to create a "role" for what I'm trying to do there as opposed to trying to set some metadata flag or something
Soheel
Soheel4mo ago
Definitely 👍 I mean you could do either
Tyler
TylerOP4mo ago
Thank you
Soheel
Soheel4mo ago
You can roll your own access control Or go with the one by better-Auth
Tyler
TylerOP4mo ago
yeah im trying to stay with some sort of best practices/framework.
Soheel
Soheel4mo ago
In the end it comes down to your needs but the better-Auth probably is more elaborate than what you need, which shouldn’t be a problem though
Tyler
TylerOP4mo ago
unfortunately one of the things with these new-er nextjs/typescript projects is that they aren't as opinionated as to some of the older tech stacks (like Drupal, etc). So it sometimes makes it difficult to know what the "best" way is lol

Did you find this page helpful?