nextauthjs / next-auth

Authentication for the Web.
https://authjs.dev
ISC License
23.15k stars 3.16k forks source link

DrizzleKit Adapter not respecting $defaultFn for user.id #10859

Open SlavenIvanov opened 1 month ago

SlavenIvanov commented 1 month ago

Adapter type

@auth/drizzle-adapter

Environment

  System:
    OS: macOS 14.3.1
    CPU: (10) arm64 Apple M1 Max
    Memory: 3.57 GB / 32.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 20.11.0 - ~/.nvm/versions/node/v20.11.0/bin/node
    Yarn: 1.22.22 - /opt/homebrew/bin/yarn
    npm: 10.2.4 - ~/.nvm/versions/node/v20.11.0/bin/npm
    bun: 1.1.4 - /opt/homebrew/bin/bun
  Browsers:
    Brave Browser: 124.1.65.130
    Chrome: 124.0.6367.119
    Safari: 17.3.1
  npmPackages:
    @auth/drizzle-adapter: ^1.0.1 => 1.0.1 
    @auth/sveltekit: ^1.0.1 => 1.0.1 ```

### Reproduction URL

https://github.com/SlavenIvanov/authjs-drizzle-issue

### Describe the issue

The DrizzleKit adapter doesn't respect the `$defaultFn()`/`$default()` set to the `user.id`  specified in the schema, during user creation.
```ts
import { nanoid } from 'nanoid'

export const users = pgTable('user', {
  id: text('id')
    .primaryKey()
    .$defaultFn(() => nanoid()), // 👈 this here
  name: text('name'),
  email: text('email').notNull(),
  emailVerified: timestamp('emailVerified', { mode: 'date' }),
  image: text('image'),
})

How to reproduce

  1. Clone repo
  2. CD into repo
  3. npm i
  4. docker-compose up -d
  5. Add your OAuth GH credentails in .env
  6. npm run drizzle:push
  7. npm run dev 👉 pageApp
  8. npm run drizzle:studio and open drizzle studio 👉 pageDrizzle
  9. now in pageApp click on Sign In
  10. Open pageDrizzle and navigate to the user table
Screenshot 2024-05-09 at 11 55 00

The Id should be a nanoid() but is a uuid And we know that the drizzle schema is correct because if you create a new user manually:

Screenshot 2024-05-09 at 11 56 02

The id is correctly picking up the nanoid()

Screenshot 2024-05-09 at 11 56 37

Expected behavior

DrizzleKit Adapter should call the $default()/$defaultFn() instead of generating a uuid for the user.id

mdecoleman commented 1 week ago

Getting the same issue with the default function being ignored in the drizzle schema and a UUID being generated regardless. Is there any work around for this?

mdecoleman commented 1 week ago

I'm currently using mysql2 with drizzle orm combined with the resend provider. I've noticed that when the email is sent for the magic link in the signIn callback prior to sending the magic link on new user, the user object is populated and has an id of uuid.

I've pulled down the source code for this lib and i can't see where that new user object is generated being passed in, however i have managed to resolve the issue.

My original next auth config looked like the following:

export const { handlers, signIn, signOut, auth } = NextAuth({
  debug: true,
  session: { strategy: "jwt" },
  providers: [Resend({ from: "no-reply@****" })],
  adapter: DrizzleAdapter(db),`

import { drizzle } from "drizzle-orm/mysql2";
import mysql from "mysql2";
import * as schema from "@/schema";

const connection = mysql.createConnection({
  user: process.env.DB_USER,
  password: process.env.DB_PASSWORD,
  host: process.env.DB_HOST,
  database: process.env.DB_NAME,
});

export const db = drizzle(connection, {
  schema,
  mode: "default",
});

I assumed that exporting the schema with the updated schema would have used my custom drizzle schema that uses a default fuction to generate a cuid2 rather than the uuid.

However it does not honor this.

I had to change the config to explicitly state the custom drizzle schemas for each table as follows:

import { DrizzleAdapter } from "@auth/drizzle-adapter";
import { eq } from "drizzle-orm";
import { userInfo, users } from "./schema";
import NextAuth, { AuthError } from "next-auth";
import Resend from "next-auth/providers/resend";
import * as schema from "@/schema";

export const { handlers, signIn, signOut, auth } = NextAuth({
  debug: true,
  session: { strategy: "jwt" },
  providers: [Resend({ from: "no-reply@***" })],
  adapter: DrizzleAdapter(db, {
    usersTable: schema.users,
    accountsTable: schema.accounts,
    authenticatorsTable: schema.authenticators,
    sessionsTable: schema.sessions,
    verificationTokensTable: schema.verificationTokens,
  }),

After changing to this it creates a new user honoring the default function and creates the CUID2 as a wanted.

It would appear that without doing this the default mysql.ts schema is used to create the user