next-auth icon indicating copy to clipboard operation
next-auth copied to clipboard

feat(adapter-drizzle): add option to pass in schema

Open juliusmarminge opened this issue 2 years ago โ€ข 13 comments

โ˜•๏ธ Reasoning

In other adapters, the adapter returns the entire table so if you have additional fields they will also be returned when the adapter queries the table. A good example here is if your user tables contains an additional field defaultCurrency, this "should" be returned from the adapter.

With drizzle, this isn't the case since the adapter is using it's own tables. This means additional fields aren't returned. This PR aims to provide an API to allow the user to pass custom tables to the adapter which will make it so the entire table is returned by the adapter and can be used in callbacks to create a session object containing the additional field(s).

I've made the changes so that they are backwards compatible. The downside to this is that if you're using custom table fn, you'll need to pass in all the tables to the object, and not just the table you have custom fields in. A perhaps better API would be

adapter: DrizzleAdapter(db, {
  tableFn: myTableFn,
  schemaOverrides: { users }
}),

but that would require a breaking change, which might be okay given the adapter is still at a 0.x version? What do you think @balazsorban44 ?

My current "workaround" is to override the getUserAndSession function to use my own table, but would be nicer to have this work ootb

import { sessions, table, users } from "~/db/schema";

export const {
  handlers: { GET, POST },
  auth,
  CSRF_experimental,
} = NextAuth({
  adapter: {
    ...DrizzleAdapter(db, table),
    async getSessionAndUser(data) {
      const sessionAndUsers = await db
        .select({
          session: sessions,
          user: users,
        })
        .from(sessions)
        .where(eq(sessions.sessionToken, data))
        .innerJoin(users, eq(users.id, sessions.userId));

      return sessionAndUsers[0] ?? null;
    },
  },
  // ...
});

๐Ÿงข Checklist

  • [x] Documentation
  • [ ] Tests (I set one up to test the types, but unsure how to test runtime behavior, I tested runtime by patching a local app to use the diff from this PR: https://github.com/juliusmarminge/time-report/pull/4)
  • [x] Ready to be merged

๐ŸŽซ Affected issues

Please scout and link issues that might be solved by this PR.

Fixes: INSERT_ISSUE_LINK_HERE

๐Ÿ“Œ Resources

juliusmarminge avatar Sep 11 '23 19:09 juliusmarminge

The latest updates on your projects. Learn more about Vercel for Git โ†—๏ธŽ

Name Status Preview Comments Updated (UTC)
auth-docs โœ… Ready (Inspect) Visit Preview ๐Ÿ’ฌ Add feedback Dec 13, 2023 0:11am
1 Ignored Deployment
Name Status Preview Comments Updated (UTC)
next-auth-docs โฌœ๏ธ Ignored (Inspect) Visit Preview Dec 13, 2023 0:11am

vercel[bot] avatar Sep 11 '23 19:09 vercel[bot]

@juliusmarminge is attempting to deploy a commit to the authjs Team on Vercel.

A member of the Team first needs to authorize it.

vercel[bot] avatar Sep 11 '23 19:09 vercel[bot]

Following the workaround in the first comment until the Drizzle adapter supports custom tables. If I added a new column called document to the users table. To remove all Typescript errors, I'm using this interface:

import { type InferSelectModel } from "drizzle-orm";
import { users } from "@/server/db/schema";

declare module "@auth/core/adapters" {
    interface AdapterUser extends InferSelectModel<typeof users> {
        // ...other properties
        document: string | null;
    }
}

nicoandrade avatar Sep 12 '23 15:09 nicoandrade

This is quite an essential feature when you want to add roles to a user. The workaround works for retrieving them. But if you want to store extra fields you also have to override the correct write functions. So yes ๐Ÿ‘๐Ÿป

geoffreydhuyvetters avatar Sep 26 '23 09:09 geoffreydhuyvetters

Can't wait for this to be implemented. Spent hours figuring out why some profile data wasn't being inserted into my custom fields ๐Ÿคฆโ€โ™‚๏ธ

yandearta avatar Oct 12 '23 06:10 yandearta

Sorry for the ping @balazsorban44, but could we get some eyes on this?

juliusmarminge avatar Oct 12 '23 06:10 juliusmarminge

+1 on this one, was confused as to why my additional columns on my Users table weren't being returned. Using the workaround for now.

iFallUpHill avatar Oct 13 '23 07:10 iFallUpHill

man why is this not merged yet :(

statusunknown418 avatar Jan 11 '24 21:01 statusunknown418

This similar PR adds support for custom table naming schema and a custom tableFn as well: https://github.com/nextauthjs/next-auth/pull/8344

ndom91 avatar Jan 12 '24 19:01 ndom91

@ndom91 looks like you're a codeowner, anything blocking this PR from going through? Happy to help fix anything if necessary

nahtnam avatar Jan 21 '24 22:01 nahtnam

BTW, one potential issue with this PR: getUserByAccount, specifically:

return dbAccount.user;

assumes that the table name is user. In my case, I'm trying to make it users to follow convention

nahtnam avatar Jan 21 '24 22:01 nahtnam

For anyone having a similar issue, you can use you own table definitions like this:

  // @ts-expect-error DrizzleAdapter expects a TableFn<SqlFlavor> but we're using a table defined in our schema
  adapter: DrizzleAdapter(db, (name: string) => {
    return {
      user: users,
      account: accounts,
      session: sessions,
      verificationToken: verificationTokens,
    }[name];
  }),

I'm sorry for the @ts-expect-error but I don't have time to create a PR for this now in the open-source project.

paupenin avatar Mar 18 '24 23:03 paupenin

It looks like this issue did not receive any activity for 60 days. It will be closed in 7 days if no further activity occurs. If you think your issue is still relevant, commenting will keep it open. Thanks!

stale[bot] avatar Jan 31 '25 23:01 stale[bot]