diff options
| author | Mohamed Bassem <me@mbassem.com> | 2025-06-21 10:44:53 +0000 |
|---|---|---|
| committer | Mohamed Bassem <me@mbassem.com> | 2025-06-21 10:45:36 +0000 |
| commit | f1f665f89cba21d4d448d27471d01a4d78a184ff (patch) | |
| tree | 61a730db28e71bdfad5d27af976f5585fe637daa | |
| parent | 6c0bcca1d5f4c72d128e8ae0298e2e896d2b2e30 (diff) | |
| download | karakeep-f1f665f89cba21d4d448d27471d01a4d78a184ff.tar.zst | |
fix: Fix oauth creation failure due to missing UserSettings table. Fixes #1583
| -rw-r--r-- | apps/web/package.json | 4 | ||||
| -rw-r--r-- | apps/web/server/auth.ts | 31 | ||||
| -rw-r--r-- | packages/trpc/routers/users.ts | 46 | ||||
| -rw-r--r-- | pnpm-lock.yaml | 45 |
4 files changed, 81 insertions, 45 deletions
diff --git a/apps/web/package.json b/apps/web/package.json index 4d4e6dfd..ff6410f6 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -17,7 +17,7 @@ "lint:fix": "next lint --fix" }, "dependencies": { - "@auth/drizzle-adapter": "^1.4.2", + "@auth/drizzle-adapter": "~1.5.0", "@emoji-mart/data": "^1.1.2", "@emoji-mart/react": "^1.1.1", "@hookform/resolvers": "^3.3.4", @@ -67,7 +67,7 @@ "lexical": "^0.20.2", "lucide-react": "^0.501.0", "next": "14.2.25", - "next-auth": "^4.24.5", + "next-auth": "^4.24.11", "next-i18next": "^15.3.1", "next-pwa": "^5.6.0", "next-themes": "^0.3.0", diff --git a/apps/web/server/auth.ts b/apps/web/server/auth.ts index 67621a17..3d32f702 100644 --- a/apps/web/server/auth.ts +++ b/apps/web/server/auth.ts @@ -1,4 +1,4 @@ -import type { Adapter } from "next-auth/adapters"; +import { Adapter, AdapterUser } from "@auth/core/adapters"; import { DrizzleAdapter } from "@auth/drizzle-adapter"; import { and, count, eq } from "drizzle-orm"; import NextAuth, { @@ -6,6 +6,7 @@ import NextAuth, { getServerSession, NextAuthOptions, } from "next-auth"; +import { Adapter as NextAuthAdapater } from "next-auth/adapters"; import CredentialsProvider from "next-auth/providers/credentials"; import { Provider } from "next-auth/providers/index"; import requestIp from "request-ip"; @@ -19,6 +20,7 @@ import { } from "@karakeep/db/schema"; import serverConfig from "@karakeep/shared/config"; import { logAuthenticationError, validatePassword } from "@karakeep/trpc/auth"; +import { createUserRaw } from "@karakeep/trpc/routers/users"; type UserRole = "admin" | "user"; @@ -70,6 +72,26 @@ async function isAdmin(email: string): Promise<boolean> { return res?.role == "admin"; } +const CustomProvider = (): Adapter => { + const adapter = DrizzleAdapter(db, { + usersTable: users, + accountsTable: accounts, + sessionsTable: sessions, + verificationTokensTable: verificationTokens, + }); + + return { + ...adapter, + createUser: async (user: Omit<AdapterUser, "id">) => { + return await createUserRaw(db, { + name: user.name ?? "", + email: user.email, + emailVerified: user.emailVerified, + }); + }, + }; +}; + const providers: Provider[] = [ CredentialsProvider({ // The name to display on the sign in form (e.g. "Sign in with...") @@ -135,12 +157,7 @@ if (oauth.wellKnownUrl) { export const authOptions: NextAuthOptions = { // https://github.com/nextauthjs/next-auth/issues/9493 - adapter: DrizzleAdapter(db, { - usersTable: users, - accountsTable: accounts, - sessionsTable: sessions, - verificationTokensTable: verificationTokens, - }) as Adapter, + adapter: CustomProvider() as NextAuthAdapater, providers: providers, session: { strategy: "jwt", diff --git a/packages/trpc/routers/users.ts b/packages/trpc/routers/users.ts index 3813387f..87923f94 100644 --- a/packages/trpc/routers/users.ts +++ b/packages/trpc/routers/users.ts @@ -31,13 +31,19 @@ import { router, } from "../index"; -export async function createUser( - input: z.infer<typeof zSignUpSchema>, - ctx: Context, - role?: "user" | "admin", +export async function createUserRaw( + db: Context["db"], + input: { + name: string; + email: string; + password?: string; + salt?: string; + role?: "user" | "admin"; + emailVerified?: Date | null; + }, ) { - return ctx.db.transaction(async (trx) => { - let userRole = role; + return await db.transaction(async (trx) => { + let userRole = input.role; if (!userRole) { const [{ count: userCount }] = await trx .select({ count: count() }) @@ -45,30 +51,31 @@ export async function createUser( userRole = userCount == 0 ? "admin" : "user"; } - const salt = generatePasswordSalt(); try { - const result = await trx + const [result] = await trx .insert(users) .values({ name: input.name, email: input.email, - password: await hashPassword(input.password, salt), - salt, + password: input.password, + salt: input.salt, role: userRole, + emailVerified: input.emailVerified, }) .returning({ id: users.id, name: users.name, email: users.email, role: users.role, + emailVerified: users.emailVerified, }); // Insert user settings for the new user await trx.insert(userSettings).values({ - userId: result[0].id, + userId: result.id, }); - return result[0]; + return result; } catch (e) { if (e instanceof SqliteError) { if (e.code == "SQLITE_CONSTRAINT_UNIQUE") { @@ -86,6 +93,21 @@ export async function createUser( }); } +export async function createUser( + input: z.infer<typeof zSignUpSchema>, + ctx: Context, + role?: "user" | "admin", +) { + const salt = generatePasswordSalt(); + return await createUserRaw(ctx.db, { + name: input.name, + email: input.email, + password: await hashPassword(input.password, salt), + salt, + role, + }); +} + export const usersAppRouter = router({ create: publicProcedure .input(zSignUpSchema) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ce81f281..5d141ed8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -507,8 +507,8 @@ importers: apps/web: dependencies: '@auth/drizzle-adapter': - specifier: ^1.4.2 - version: 1.4.2 + specifier: ~1.5.0 + version: 1.5.3 '@emoji-mart/data': specifier: ^1.1.2 version: 1.1.2 @@ -657,8 +657,8 @@ importers: specifier: 14.2.25 version: 14.2.25(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.89.1) next-auth: - specifier: ^4.24.5 - version: 4.24.6(next@14.2.25(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.89.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: ^4.24.11 + version: 4.24.11(next@14.2.25(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.89.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) next-i18next: specifier: ^15.3.1 version: 15.3.1(i18next@23.16.5)(next@14.2.25(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.89.1))(react-i18next@15.1.1(i18next@23.16.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) @@ -1512,8 +1512,8 @@ packages: nodemailer: optional: true - '@auth/core@0.34.2': - resolution: {integrity: sha512-KywHKRgLiF3l7PLyL73fjLSIBe1YNcA6sMeew4yMP6cfCWGXZrkkXd32AjRi1hlJ9nvovUBGZHvbn+LijO6ZeQ==} + '@auth/core@0.35.3': + resolution: {integrity: sha512-g6qfiqU4OtyvIEZ8J7UoIwAxEnNnLJV0/f/DW41U+4G5nhBlaCrnKhawJIJpU0D3uavXLeDT3B0BkjtiimvMDA==} peerDependencies: '@simplewebauthn/browser': ^9.0.1 '@simplewebauthn/server': ^9.0.2 @@ -1526,8 +1526,8 @@ packages: nodemailer: optional: true - '@auth/drizzle-adapter@1.4.2': - resolution: {integrity: sha512-rqukaT9CeWB8VOt6g2bQ6uYMHVOQIYCBkzddZXWshi8aqwLABatpRWAc+pehpcMDn0RSW/uvKMs7tkON+Bho9Q==} + '@auth/drizzle-adapter@1.5.3': + resolution: {integrity: sha512-VNyYb1hiGtorJhCjShtncjN3TKXxtwxOwphYecq8lZSVuFDLIWHhp4ZbdZDjnmkvEk8G66IpFrYW84qpt+WUIg==} '@babel/code-frame@7.10.4': resolution: {integrity: sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==} @@ -6507,10 +6507,6 @@ packages: resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} engines: {node: '>=6.6.0'} - cookie@0.5.0: - resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==} - engines: {node: '>= 0.6'} - cookie@0.6.0: resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==} engines: {node: '>= 0.6'} @@ -10554,14 +10550,17 @@ packages: resolution: {integrity: sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==} engines: {node: '>= 0.4.0'} - next-auth@4.24.6: - resolution: {integrity: sha512-djQt3ZEaWEIxcsuh3HTW2uuzLfXMRjHH+ugAsichlQSbH4iA5MRcgMA2HvTNvsDTDLh44tyU72+/gWsxgTbAKg==} + next-auth@4.24.11: + resolution: {integrity: sha512-pCFXzIDQX7xmHFs4KVH4luCjaCbuPRtZ9oBUjUhOk84mZ9WVPf94n87TxYI4rSRf9HmfHEF8Yep3JrYDVOo3Cw==} peerDependencies: - next: ^12.2.5 || ^13 || ^14 + '@auth/core': 0.34.2 + next: ^12.2.5 || ^13 || ^14 || ^15 nodemailer: ^6.6.5 - react: ^17.0.2 || ^18 - react-dom: ^17.0.2 || ^18 + react: ^17.0.2 || ^18 || ^19 + react-dom: ^17.0.2 || ^18 || ^19 peerDependenciesMeta: + '@auth/core': + optional: true nodemailer: optional: true @@ -14775,7 +14774,7 @@ snapshots: preact: 10.11.3 preact-render-to-string: 5.2.3(preact@10.11.3) - '@auth/core@0.34.2': + '@auth/core@0.35.3': dependencies: '@panva/hkdf': 1.2.1 '@types/cookie': 0.6.0 @@ -14785,9 +14784,9 @@ snapshots: preact: 10.11.3 preact-render-to-string: 5.2.3(preact@10.11.3) - '@auth/drizzle-adapter@1.4.2': + '@auth/drizzle-adapter@1.5.3': dependencies: - '@auth/core': 0.34.2 + '@auth/core': 0.35.3 transitivePeerDependencies: - '@simplewebauthn/browser' - '@simplewebauthn/server' @@ -22080,8 +22079,6 @@ snapshots: cookie-signature@1.2.2: {} - cookie@0.5.0: {} - cookie@0.6.0: {} cookie@0.7.1: {} @@ -27300,11 +27297,11 @@ snapshots: netmask@2.0.2: {} - next-auth@4.24.6(next@14.2.25(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.89.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + next-auth@4.24.11(next@14.2.25(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.89.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: '@babel/runtime': 7.27.6 '@panva/hkdf': 1.2.1 - cookie: 0.5.0 + cookie: 0.7.2 jose: 4.15.9 next: 14.2.25(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.89.1) oauth: 0.9.15 |
