BA
Better Auth•3w ago
KHRM

Setting Admin Roll With Hook

hooks: {
before: createAuthMiddleware(async (ctx) => {
if (ctx.path === "/sign-up/email") {
const email = ctx.body.email.trim().toLowerCase();

const ADMIN_EMAILS = process.env.ADMIN_EMAILS?.split(";") ?? [];
if (ADMIN_EMAILS.includes(email)) {
ctx.body.role = UserRole.ADMIN;
} else {
ctx.body.role = UserRole.USER;
}

console.log(ctx.body);
}

console.log("ctx.path", ctx.path);
}),
},
hooks: {
before: createAuthMiddleware(async (ctx) => {
if (ctx.path === "/sign-up/email") {
const email = ctx.body.email.trim().toLowerCase();

const ADMIN_EMAILS = process.env.ADMIN_EMAILS?.split(";") ?? [];
if (ADMIN_EMAILS.includes(email)) {
ctx.body.role = UserRole.ADMIN;
} else {
ctx.body.role = UserRole.USER;
}

console.log(ctx.body);
}

console.log("ctx.path", ctx.path);
}),
},
here is my hook in my auth config i checked that ctx.body.role = 'ADMIN' throughout this hook but when the user is created in my database their role is 'USER' I assume this comes from my @default(USER) on my prisma schema but why is this occuring if the role is set to user via the before hook? originally I had this logic in databaseHooks but I moved it to hooks so that I can use the required: true flag on the [user][additional fields] /* for now ill move logic back to databaseHooks */
13 Replies
KHRM
KHRMOP•3w ago
update i thought i found my mistake by not returning a context, as so
hooks: {
before: createAuthMiddleware(async (ctx) => {
if (ctx.path === "/sign-up/email") {
const email = ctx.body.email.trim().toLowerCase();
let role: UserRole = UserRole.USER;

const ADMIN_EMAILS = process.env.ADMIN_EMAILS?.split(";") ?? [];
if (ADMIN_EMAILS.includes(email)) {
role = UserRole.ADMIN;
}

return {
context: {
...ctx,
body: {
...ctx.body,
name: email.split("@")[0],
role,
},
},
};
}
}),
},
hooks: {
before: createAuthMiddleware(async (ctx) => {
if (ctx.path === "/sign-up/email") {
const email = ctx.body.email.trim().toLowerCase();
let role: UserRole = UserRole.USER;

const ADMIN_EMAILS = process.env.ADMIN_EMAILS?.split(";") ?? [];
if (ADMIN_EMAILS.includes(email)) {
role = UserRole.ADMIN;
}

return {
context: {
...ctx,
body: {
...ctx.body,
name: email.split("@")[0],
role,
},
},
};
}
}),
},
but ALAS the name gets changed but the role is still "USER" 😦 bump
Ping
Ping•3w ago
Are you sure your logic is correct and that if statement does return true for role to be admin?
KHRM
KHRMOP•3w ago
Pretty sure I did console logging throughout the hook I can try again since I moved the logic for role to database hooks I added the name just to show a 1-1 parallel and the name does get changed
Ping
Ping•3w ago
Might be easier to test if you can hardcode role in the return to just be ADMIN and see if that works.
KHRM
KHRMOP•3w ago
no dice
hooks: {
before: createAuthMiddleware(async (ctx) => {
if (ctx.path === "/sign-up/email") {
console.log({
body: {
...ctx.body,
name: "mitochondria is the powerhouse of the cell",
role: "admin",
},
});

return {
context: {
...ctx,
body: {
...ctx.body,
name: "mitochondria is the powerhouse of the cell",
role: "admin",
},
},
};
}
}),
},
hooks: {
before: createAuthMiddleware(async (ctx) => {
if (ctx.path === "/sign-up/email") {
console.log({
body: {
...ctx.body,
name: "mitochondria is the powerhouse of the cell",
role: "admin",
},
});

return {
context: {
...ctx,
body: {
...ctx.body,
name: "mitochondria is the powerhouse of the cell",
role: "admin",
},
},
};
}
}),
},
No description
KHRM
KHRMOP•3w ago
No description
KHRM
KHRMOP•7d ago
this is how sign up is being called originally for reference although i assume this happens before the hook
"use server";

import { auth, type ErrorTypes } from "@/lib/auth";
import { APIError } from "better-auth/api";

type ActionState =
| { success: true; error: null }
| { success: false; error: string };

export async function signUpAction(body: {
name: string;
email: string;
password: string;
}): Promise<ActionState> {
try {
await auth.api.signUpEmail({
body: {
...body,
callbackURL: "/auth/sign-in",
},
});

return { success: true, error: null };
} catch (err) {
...
}
}
"use server";

import { auth, type ErrorTypes } from "@/lib/auth";
import { APIError } from "better-auth/api";

type ActionState =
| { success: true; error: null }
| { success: false; error: string };

export async function signUpAction(body: {
name: string;
email: string;
password: string;
}): Promise<ActionState> {
try {
await auth.api.signUpEmail({
body: {
...body,
callbackURL: "/auth/sign-in",
},
});

return { success: true, error: null };
} catch (err) {
...
}
}
@Ping still curious about this if you have the chance to check
Ping
Ping•7d ago
Why not use database hooks again? @KHRM
KHRM
KHRMOP•6d ago
no particular reason i just want to know if im doing something wrong if i use hooks or even hard code it in the sign up
<Button
type="submit"
className="w-full"
disabled={loading}
onClick={async () => {
await signUp.email({
email,
password,
name: `${firstName} ${lastName}`,
image: image ? await convertImageToBase64(image) : "",
role: "ADMIN",
callbackURL: "/dashboard",
fetchOptions: {
onResponse: () => {
setLoading(false);
},
onRequest: () => {
setLoading(true);
},
onError: (ctx) => {
toast.error(ctx.error.message);
},
onSuccess: async () => {
router.push("/dashboard");
},
},
});
}}
>
<Button
type="submit"
className="w-full"
disabled={loading}
onClick={async () => {
await signUp.email({
email,
password,
name: `${firstName} ${lastName}`,
image: image ? await convertImageToBase64(image) : "",
role: "ADMIN",
callbackURL: "/dashboard",
fetchOptions: {
onResponse: () => {
setLoading(false);
},
onRequest: () => {
setLoading(true);
},
onError: (ctx) => {
toast.error(ctx.error.message);
},
onSuccess: async () => {
router.push("/dashboard");
},
},
});
}}
>
it just always is role USER
Ping
Ping•5d ago
The admin plugin overwrites this, it makes sense because you wouldn't want malicious users be able to control the role to sign up via front-end. If you can use a database hook - after hook, you can check if the email matches your list, then use your ORM to update their role.
KHRM
KHRMOP•5d ago
I see fors the option of adminIds in the admin plugin override the role in the database? Or will set their role upon sign up although that kind of wouldn't make sense because you wouldn't know the id in advance Basically database hooks is the intended way to work with role with admin plugin If I'm not using admin plugin I could pass it via the sign up or a regular hook?
Ping
Ping•5d ago
Yes, just as long as you're aware that it can be dangerous for the front-end to determine the role of a user You'll have to code everything yourself - outside the admin plugin.
KHRM
KHRMOP•5d ago
Got it thanks for clarifying why it was getting 'overridden'

Did you find this page helpful?