KHRM
KHRM
Explore posts from servers
BABetter Auth
Created by KHRM on 4/12/2025 in #help
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 */
12 replies
BABetter Auth
Created by KHRM on 4/12/2025 in #help
Typing Role
No description
13 replies
BABetter Auth
Created by KHRM on 4/11/2025 in #help
Implementing User Roles
Hello, I am trying to implement roles of USER, MODERATOR, or ADMIN I find the admin and organization plugins a bit intimidating but more importantly I am not sure if they are the exact use case for my roles here is my current code
export const auth = betterAuth({
database: prismaAdapter(prisma, {
provider: "postgresql",
}),
...
user: {
additionalFields: {
role: {
type: "string",
required: false,
input: false,
},
},
},
databaseHooks: {
user: {
create: {
before: async (user) => {
const ADMIN_EMAILS = process.env.ADMIN_EMAILS?.split(";") || [];

if (ADMIN_EMAILS.includes(user.email)) {
return { data: { ...user, role: UserRole.ADMIN } };
}

const MODERATOR_EMAILS =
process.env.MODERATOR_EMAILS?.split(";") || [];
if (MODERATOR_EMAILS.includes(user.email)) {
return { data: { ...user, role: UserRole.MODERATOR } };
}

return { data: user };
},
},
},
}
});
export const auth = betterAuth({
database: prismaAdapter(prisma, {
provider: "postgresql",
}),
...
user: {
additionalFields: {
role: {
type: "string",
required: false,
input: false,
},
},
},
databaseHooks: {
user: {
create: {
before: async (user) => {
const ADMIN_EMAILS = process.env.ADMIN_EMAILS?.split(";") || [];

if (ADMIN_EMAILS.includes(user.email)) {
return { data: { ...user, role: UserRole.ADMIN } };
}

const MODERATOR_EMAILS =
process.env.MODERATOR_EMAILS?.split(";") || [];
if (MODERATOR_EMAILS.includes(user.email)) {
return { data: { ...user, role: UserRole.MODERATOR } };
}

return { data: user };
},
},
},
}
});
Is this a good approach? I have the default role as USER Or should I be using the admin or organization plugins and adjusting them to fit my above requirements?
6 replies
BABetter Auth
Created by KHRM on 4/9/2025 in #help
set cookie manually in next.js server action
"use server";

import { auth } from "@/auth";
import { cookies } from "next/headers";

export async function signInAction({
email,
password,
}: {
email: string;
password: string;
}) {
const res = await auth.api.signInEmail({
body: {
email,
password,
},
asResponse: true,
});



const cookieStore = await cookies();
const sessionCookieFull = res.headers.get("set-cookie");
if (sessionCookieFull) {
const [sessionCookie, _maxAge, _path, _httpOnly, _sameSite] =
sessionCookieFull.split(";").map((part) => part.trim());

const [key, value] = sessionCookie.split("=");
const maxAge = _maxAge.split("=")[1];
const path = _path.split("=")[1];
const httpOnly = Boolean(_httpOnly.split("=")[1]);
const sameSite = _sameSite.split("=")[1];
console.log({ key, value, maxAge, path, httpOnly, sameSite });
cookieStore.delete(key);
cookieStore.set(key, value, {
maxAge: Number(maxAge),
path,
httpOnly: true,
...(sameSite === "Lax" ? { sameSite: "lax" } : {}),
});
}
}
"use server";

import { auth } from "@/auth";
import { cookies } from "next/headers";

export async function signInAction({
email,
password,
}: {
email: string;
password: string;
}) {
const res = await auth.api.signInEmail({
body: {
email,
password,
},
asResponse: true,
});



const cookieStore = await cookies();
const sessionCookieFull = res.headers.get("set-cookie");
if (sessionCookieFull) {
const [sessionCookie, _maxAge, _path, _httpOnly, _sameSite] =
sessionCookieFull.split(";").map((part) => part.trim());

const [key, value] = sessionCookie.split("=");
const maxAge = _maxAge.split("=")[1];
const path = _path.split("=")[1];
const httpOnly = Boolean(_httpOnly.split("=")[1]);
const sameSite = _sameSite.split("=")[1];
console.log({ key, value, maxAge, path, httpOnly, sameSite });
cookieStore.delete(key);
cookieStore.set(key, value, {
maxAge: Number(maxAge),
path,
httpOnly: true,
...(sameSite === "Lax" ? { sameSite: "lax" } : {}),
});
}
}
I know there is a plugin to do this for me but i wanted to see if i could do it manually, i compared it to the cookie when i use the client instance and it seems pretty similar but my session is still undefined do i have to use the plugin or am i missing something? i think i normalized enough to properly set the cookie
7 replies
BABetter Auth
Created by KHRM on 1/14/2025 in #help
Adjusting Default User
By default it seems the user with drizzle adapter is just select * from user but i dont want to return specific fields like updatedAt, where is this logic being done and how can i change it?
2 replies
PPrisma
Created by KHRM on 10/3/2024 in #help-and-questions
Sorting by Relations
Hello, I am trying to introduce infinite scrolling im my application but I am running into an issue. I am using Prisma ORM with sqlite through Turso here is what I curently have
const events = await db.event.findMany({
include: {
eventDates: {
orderBy: {
date: {
date: "asc",
},
},
include: { date: true },
},
},
skip,
take,
cursor,
});

const sortedEvents = events.sort((a, b) => {
const aDate = a.eventDates[0].date.date.getTime();
const bDate = b.eventDates[0].date.date.getTime();

return aDate - bDate;
});
const events = await db.event.findMany({
include: {
eventDates: {
orderBy: {
date: {
date: "asc",
},
},
include: { date: true },
},
},
skip,
take,
cursor,
});

const sortedEvents = events.sort((a, b) => {
const aDate = a.eventDates[0].date.date.getTime();
const bDate = b.eventDates[0].date.date.getTime();

return aDate - bDate;
});
I sort the events after I get them, but if I am only grabbing 5 results at a time, its only going to sort those 5 (which means it may be sorted within itself, but it might not be the 5 earliest events) here is a simplified version of my schema
model Event {
eventId String @id @default(cuid()) @map("event_id")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @default(now()) @updatedAt @map("updated_at")
title String
eventDates EventDate[]
@@map("events")
}

model EventDate {
event Event @relation(fields: [eventId], references: [eventId])
eventId String @map("event_id")
date Date @relation(fields: [dateId], references: [dateId])
dateId Int @map("date_id")

@@unique([eventId, dateId])
@@map("event_dates")
}

model Date {
dateId Int @id @default(autoincrement()) @map("date_id")
date DateTime @unique
eventDates EventDate[]
@@map("dates")
}
model Event {
eventId String @id @default(cuid()) @map("event_id")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @default(now()) @updatedAt @map("updated_at")
title String
eventDates EventDate[]
@@map("events")
}

model EventDate {
event Event @relation(fields: [eventId], references: [eventId])
eventId String @map("event_id")
date Date @relation(fields: [dateId], references: [dateId])
dateId Int @map("date_id")

@@unique([eventId, dateId])
@@map("event_dates")
}

model Date {
dateId Int @id @default(autoincrement()) @map("date_id")
date DateTime @unique
eventDates EventDate[]
@@map("dates")
}
How can I get all events sorted by their first event date, whcih is sorted by their date example query result
console.log(events[0])
console.log(events[0])
{
eventId: 'cm1s1bcxo0029jzxzoivivxr7',
createdAt: 2024-10-02T15:40:54.972Z,
updatedAt: 2024-10-02T15:40:54.972Z,
title: 'AXCN: Mobile Suit Gundam',
eventDates: [
{
eventId: 'cm1s1bcxo0029jzxzoivivxr7',
dateId: 105,
date: { dateId: 105, date: 2024-10-02T00:00:00.000Z }
},
{
eventId: 'cm1s1bcxo0029jzxzoivivxr7',
dateId: 106,
date: { dateId: 106, date: 2024-10-06T00:00:00.000Z }
}
]
{
eventId: 'cm1s1bcxo0029jzxzoivivxr7',
createdAt: 2024-10-02T15:40:54.972Z,
updatedAt: 2024-10-02T15:40:54.972Z,
title: 'AXCN: Mobile Suit Gundam',
eventDates: [
{
eventId: 'cm1s1bcxo0029jzxzoivivxr7',
dateId: 105,
date: { dateId: 105, date: 2024-10-02T00:00:00.000Z }
},
{
eventId: 'cm1s1bcxo0029jzxzoivivxr7',
dateId: 106,
date: { dateId: 106, date: 2024-10-06T00:00:00.000Z }
}
]
note eventDates array may not necessarily be in order but this is covered by
include: {
eventDates: {
orderBy: {
date: {
date: "asc",
},
},
include: { date: true },
},
},
include: {
eventDates: {
orderBy: {
date: {
date: "asc",
},
},
include: { date: true },
},
},
38 replies
DTDrizzle Team
Created by KHRM on 5/5/2024 in #help
Auth.js (next-auth) with Drizzle Provider Typescript
Hello so in the guide for the drizzle provider for Auth.js (next-auth) it says we can override the tables for example if i want to give me my users table a password and role field but then i run into a typescript error since the tables are typed in a specific way inside the adapter itself
adapter: {
/**
* Argument of type '{ usersTable: SQLiteTableWithColumns<{ name: "user"; schema: undefined; columns: { id: SQLiteColumn<{ name: "id"; tableName: "user"; dataType: "string"; columnType: "SQLiteText"; data: string; driverParam: string; notNull: true; hasDefault: true; enumValues: [...]; baseColumn: never; }, object>; ... 5 more ...; role...' is not assignable to parameter of type 'DefaultSQLiteSchema'.
Type '{ usersTable: SQLiteTableWithColumns<{ name: "user"; schema: undefined; columns: { id: SQLiteColumn<{ name: "id"; tableName: "user"; dataType: "string"; columnType: "SQLiteText"; data: string; driverParam: string; notNull: true; hasDefault: true; enumValues: [...]; baseColumn: never; }, object>; ... 5 more ...; role...' is missing the following properties from type 'DefaultSQLiteSchema': accountsTable, sessionsTable, verificationTokensTablets(2345)
*/
...DrizzleAdapter(db, { usersTable: users }),
adapter: {
/**
* Argument of type '{ usersTable: SQLiteTableWithColumns<{ name: "user"; schema: undefined; columns: { id: SQLiteColumn<{ name: "id"; tableName: "user"; dataType: "string"; columnType: "SQLiteText"; data: string; driverParam: string; notNull: true; hasDefault: true; enumValues: [...]; baseColumn: never; }, object>; ... 5 more ...; role...' is not assignable to parameter of type 'DefaultSQLiteSchema'.
Type '{ usersTable: SQLiteTableWithColumns<{ name: "user"; schema: undefined; columns: { id: SQLiteColumn<{ name: "id"; tableName: "user"; dataType: "string"; columnType: "SQLiteText"; data: string; driverParam: string; notNull: true; hasDefault: true; enumValues: [...]; baseColumn: never; }, object>; ... 5 more ...; role...' is missing the following properties from type 'DefaultSQLiteSchema': accountsTable, sessionsTable, verificationTokensTablets(2345)
*/
...DrizzleAdapter(db, { usersTable: users }),
4 replies
KKinde
Created by KHRM on 4/11/2024 in #💻┃support
useKindeBrowserClient shows error
Hello, I am using the useKindeBrowser client to recieve the isAuthenticated property
"use client";

import { useKindeBrowserClient } from "@kinde-oss/kinde-auth-nextjs";
import { LoginLink } from "@kinde-oss/kinde-auth-nextjs/components";
import Link from "next/link";
import { Button } from "@/components/ui/button";

export const GetStartedBtn = () => {
const { isAuthenticated } = useKindeBrowserClient();

return (
<Button variant="secondary" size="lg" asChild>
{isAuthenticated ? (
<Link href="/journal">Get Started</Link>
) : (
<LoginLink postLoginRedirectURL="/login/redirect">
Get Started
</LoginLink>
)}
</Button>
);
};
"use client";

import { useKindeBrowserClient } from "@kinde-oss/kinde-auth-nextjs";
import { LoginLink } from "@kinde-oss/kinde-auth-nextjs/components";
import Link from "next/link";
import { Button } from "@/components/ui/button";

export const GetStartedBtn = () => {
const { isAuthenticated } = useKindeBrowserClient();

return (
<Button variant="secondary" size="lg" asChild>
{isAuthenticated ? (
<Link href="/journal">Get Started</Link>
) : (
<LoginLink postLoginRedirectURL="/login/redirect">
Get Started
</LoginLink>
)}
</Button>
);
};
however when i am not logged in on the home page there is an error shown in the console.log is this intended behavior?, i just started my project and it already feels wrong haha (error is not shown if i am logged in)
✓ Compiled in 232ms (1085 modules)
Error: Cannot get user details, no authentication credential found
at eval (webpack-internal:///(rsc)/./node_modules/.pnpm/@[email protected]/node_modules/@kinde-oss/kinde-typescript-sdk/dist/sdk/clients/server/authorization-code.js:166:31)
at step (webpack-internal:///(rsc)/./node_modules/.pnpm/@[email protected]/node_modules/@kinde-oss/kinde-typescript-sdk/dist/sdk/clients/server/authorization-code.js:50:23)
at Object.eval [as next] (webpack-internal:///(rsc)/./node_modules/.pnpm/@[email protected]/node_modules/@kinde-oss/kinde-typescript-sdk/dist/sdk/clients/server/authorization-code.js:31:53)
at fulfilled (webpack-internal:///(rsc)/./node_modules/.pnpm/@[email protected]/node_modules/@kinde-oss/kinde-typescript-sdk/dist/sdk/clients/server/authorization-code.js:22:58)
Error: Cannot get user details, no authentication credential found
at eval (webpack-internal:///(rsc)/./node_modules/.pnpm/@kinde-oss+kinde-typesc...
✓ Compiled in 232ms (1085 modules)
Error: Cannot get user details, no authentication credential found
at eval (webpack-internal:///(rsc)/./node_modules/.pnpm/@[email protected]/node_modules/@kinde-oss/kinde-typescript-sdk/dist/sdk/clients/server/authorization-code.js:166:31)
at step (webpack-internal:///(rsc)/./node_modules/.pnpm/@[email protected]/node_modules/@kinde-oss/kinde-typescript-sdk/dist/sdk/clients/server/authorization-code.js:50:23)
at Object.eval [as next] (webpack-internal:///(rsc)/./node_modules/.pnpm/@[email protected]/node_modules/@kinde-oss/kinde-typescript-sdk/dist/sdk/clients/server/authorization-code.js:31:53)
at fulfilled (webpack-internal:///(rsc)/./node_modules/.pnpm/@[email protected]/node_modules/@kinde-oss/kinde-typescript-sdk/dist/sdk/clients/server/authorization-code.js:22:58)
Error: Cannot get user details, no authentication credential found
at eval (webpack-internal:///(rsc)/./node_modules/.pnpm/@kinde-oss+kinde-typesc...
2 replies