Try to hack auth

This commit is contained in:
Jared Palmer 2023-06-02 11:15:04 -04:00
parent d88eae7230
commit 030b23985d
19 changed files with 330 additions and 673 deletions

View file

@ -1,4 +0,0 @@
import { drizzle } from "drizzle-orm/vercel-postgres";
import { sql } from "@vercel/postgres";
export const db = drizzle(sql);

View file

@ -9,15 +9,14 @@
* ## Installation
*
* ```bash npm2yarn2pnpm
* npm install next-auth drizzle-orm @next-auth/drizzle-adapter
* npm install next-auth drizzle-orm @auth/drizzle-adapter
* npm install drizzle-kit --save-dev
* ```
*
* @module @next-auth/drizzle-adapter
* @module @auth/drizzle-adapter
*/
import type { Adapter } from "@auth/nextjs/adapters";
import type { Adapter } from "@auth/core/adapters";
import { and, eq } from "drizzle-orm";
import { v4 as uuid } from "uuid";
import type { DbClient, Schema } from "./schema";
/**
@ -28,7 +27,7 @@ import type { DbClient, Schema } from "./schema";
* ```js title="pages/api/auth/[...nextauth].js"
* import NextAuth from "next-auth"
* import GoogleProvider from "next-auth/providers/google"
* import { DrizzleAdapter } from "@next-auth/drizzle-adapter"
* import { DrizzleAdapter } from "@auth/drizzle-adapter"
* import { db } from "./db-schema"
*
* export default NextAuth({
@ -109,7 +108,7 @@ import type { DbClient, Schema } from "./schema";
* ```
*
**/
export function DrizzleAdapterPg(
export function PgAdapter(
client: DbClient,
{ users, sessions, verificationTokens, accounts }: Schema
): Adapter {
@ -117,7 +116,7 @@ export function DrizzleAdapterPg(
createUser: async (data) => {
return client
.insert(users)
.values({ ...data, id: uuid() })
.values({ ...data, id: crypto.randomUUID() as string })
.returning()
.then((res) => res[0]);
},
@ -188,7 +187,7 @@ export function DrizzleAdapterPg(
// Drizzle will return `null` for fields that are not defined.
// However, the return type is expecting `undefined`.
const account: ReturnType<Adapter["linkAccount"]> = {
const account = {
...updatedAccount,
access_token: updatedAccount.access_token ?? undefined,
token_type: updatedAccount.token_type ?? undefined,
@ -202,20 +201,19 @@ export function DrizzleAdapterPg(
return account;
},
getUserByAccount: async (account) => {
const user =
(await client
.select()
.from(users)
.innerJoin(
accounts,
and(
eq(accounts.providerAccountId, account.providerAccountId),
eq(accounts.provider, account.provider)
)
const dbAccount = await client
.select()
.from(accounts)
.where(
and(
eq(accounts.providerAccountId, account.providerAccountId),
eq(accounts.provider, account.provider)
)
.then((res) => res[0])) ?? null;
)
.leftJoin(users, eq(accounts.userId, users.id))
.then((res) => res[0]);
return user.users;
return dbAccount.users;
},
deleteSession: async (sessionToken) => {
await client

View file

@ -15,23 +15,23 @@ CREATE TABLE IF NOT EXISTS "accounts" (
ALTER TABLE "accounts" ADD CONSTRAINT "accounts_provider_providerAccountId" PRIMARY KEY("provider","providerAccountId");
CREATE TABLE IF NOT EXISTS "sessions" (
"sessionToken" text PRIMARY KEY NOT NULL,
"userId" text NOT NULL,
"expires" timestamp NOT NULL
"sessionToken" text PRIMARY KEY NOT NULL,
"expires" integer NOT NULL
);
CREATE TABLE IF NOT EXISTS "users" (
"id" text PRIMARY KEY NOT NULL,
"name" text,
"email" text NOT NULL,
"emailVerified" timestamp,
"emailVerified" integer,
"image" text
);
CREATE TABLE IF NOT EXISTS "verificationToken" (
"identifier" text NOT NULL,
"token" text NOT NULL,
"expires" timestamp NOT NULL
"expires" integer NOT NULL
);
--> statement-breakpoint
ALTER TABLE "verificationToken" ADD CONSTRAINT "verificationToken_identifier_token" PRIMARY KEY("identifier","token");

View file

@ -1,7 +0,0 @@
ALTER TABLE "accounts" DROP CONSTRAINT "accounts_provider_providerAccountId";
ALTER TABLE "verificationToken" DROP CONSTRAINT "verificationToken_identifier_token";
CREATE UNIQUE INDEX IF NOT EXISTS "Account_provider_providerAccountId_key" ON "accounts" ("provider","providerAccountId");
CREATE UNIQUE INDEX IF NOT EXISTS "Session_sessionToken_key" ON "sessions" ("sessionToken");
CREATE UNIQUE INDEX IF NOT EXISTS "User_email_key" ON "users" ("email");
CREATE UNIQUE INDEX IF NOT EXISTS "VerificationToken_identifier_token_key" ON "verificationToken" ("identifier","token");
CREATE UNIQUE INDEX IF NOT EXISTS "VerificationToken_token_key" ON "verificationToken" ("token");

View file

@ -0,0 +1,11 @@
CREATE TABLE IF NOT EXISTS "chats" (
"id" text PRIMARY KEY NOT NULL,
"role" text NOT NULL,
"userId" text NOT NULL
);
DO $$ BEGIN
ALTER TABLE "chats" ADD CONSTRAINT "chats_userId_users_id_fk" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE no action ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;

View file

@ -1,7 +1,7 @@
{
"version": "5",
"dialect": "pg",
"id": "ea430ef9-8e30-4cb6-9985-d03f43656cf8",
"id": "c6cb6121-2dc1-49be-8bd9-62f1c0c55939",
"prevId": "00000000-0000-0000-0000-000000000000",
"tables": {
"accounts": {
@ -105,21 +105,21 @@
"name": "sessions",
"schema": "",
"columns": {
"sessionToken": {
"name": "sessionToken",
"type": "text",
"primaryKey": true,
"notNull": true
},
"userId": {
"name": "userId",
"type": "text",
"primaryKey": false,
"notNull": true
},
"sessionToken": {
"name": "sessionToken",
"type": "text",
"primaryKey": true,
"notNull": true
},
"expires": {
"name": "expires",
"type": "timestamp",
"type": "integer",
"primaryKey": false,
"notNull": true
}
@ -166,7 +166,7 @@
},
"emailVerified": {
"name": "emailVerified",
"type": "timestamp",
"type": "integer",
"primaryKey": false,
"notNull": false
},
@ -199,7 +199,7 @@
},
"expires": {
"name": "expires",
"type": "timestamp",
"type": "integer",
"primaryKey": false,
"notNull": true
}

View file

@ -1,8 +1,8 @@
{
"version": "5",
"dialect": "pg",
"id": "34122d24-88e0-430e-862c-2168b0f866cb",
"prevId": "ea430ef9-8e30-4cb6-9985-d03f43656cf8",
"id": "ad52915b-d697-4935-9373-97dca163dd91",
"prevId": "c6cb6121-2dc1-49be-8bd9-62f1c0c55939",
"tables": {
"accounts": {
"name": "accounts",
@ -75,16 +75,7 @@
"notNull": false
}
},
"indexes": {
"Account_provider_providerAccountId_key": {
"name": "Account_provider_providerAccountId_key",
"columns": [
"provider",
"providerAccountId"
],
"isUnique": true
}
},
"indexes": {},
"foreignKeys": {
"accounts_userId_users_id_fk": {
"name": "accounts_userId_users_id_fk",
@ -100,40 +91,81 @@
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {}
"compositePrimaryKeys": {
"accounts_provider_providerAccountId": {
"name": "accounts_provider_providerAccountId",
"columns": [
"provider",
"providerAccountId"
]
}
}
},
"sessions": {
"name": "sessions",
"chats": {
"name": "chats",
"schema": "",
"columns": {
"sessionToken": {
"name": "sessionToken",
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true
},
"role": {
"name": "role",
"type": "text",
"primaryKey": false,
"notNull": true
},
"userId": {
"name": "userId",
"type": "text",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"chats_userId_users_id_fk": {
"name": "chats_userId_users_id_fk",
"tableFrom": "chats",
"tableTo": "users",
"columnsFrom": [
"userId"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {}
},
"sessions": {
"name": "sessions",
"schema": "",
"columns": {
"userId": {
"name": "userId",
"type": "text",
"primaryKey": false,
"notNull": true
},
"sessionToken": {
"name": "sessionToken",
"type": "text",
"primaryKey": true,
"notNull": true
},
"expires": {
"name": "expires",
"type": "timestamp",
"type": "integer",
"primaryKey": false,
"notNull": true
}
},
"indexes": {
"Session_sessionToken_key": {
"name": "Session_sessionToken_key",
"columns": [
"sessionToken"
],
"isUnique": true
}
},
"indexes": {},
"foreignKeys": {
"sessions_userId_users_id_fk": {
"name": "sessions_userId_users_id_fk",
@ -175,7 +207,7 @@
},
"emailVerified": {
"name": "emailVerified",
"type": "timestamp",
"type": "integer",
"primaryKey": false,
"notNull": false
},
@ -186,15 +218,7 @@
"notNull": false
}
},
"indexes": {
"User_email_key": {
"name": "User_email_key",
"columns": [
"email"
],
"isUnique": true
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {}
},
@ -216,30 +240,22 @@
},
"expires": {
"name": "expires",
"type": "timestamp",
"type": "integer",
"primaryKey": false,
"notNull": true
}
},
"indexes": {
"VerificationToken_identifier_token_key": {
"name": "VerificationToken_identifier_token_key",
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {
"verificationToken_identifier_token": {
"name": "verificationToken_identifier_token",
"columns": [
"identifier",
"token"
],
"isUnique": true
},
"VerificationToken_token_key": {
"name": "VerificationToken_token_key",
"columns": [
"token"
],
"isUnique": true
]
}
},
"foreignKeys": {},
"compositePrimaryKeys": {}
}
}
},
"enums": {},

View file

@ -5,15 +5,15 @@
{
"idx": 0,
"version": "5",
"when": 1684771069602,
"tag": "0000_flawless_moondragon",
"when": 1685716228240,
"tag": "0000_clammy_freak",
"breakpoints": false
},
{
"idx": 1,
"version": "5",
"when": 1684771628481,
"tag": "0001_colorful_spectrum",
"when": 1685716937211,
"tag": "0001_petite_sue_storm",
"breakpoints": false
}
]

View file

@ -1,28 +1,23 @@
import {
integer,
timestamp,
pgTable,
text,
primaryKey,
uniqueIndex,
} from "drizzle-orm/pg-core";
import { drizzle } from "drizzle-orm/vercel-postgres";
import { sql } from "@vercel/postgres";
import { ProviderType } from "@auth/nextjs/providers";
import { sql } from "@vercel/postgres";
import { relations } from "drizzle-orm";
import { integer, pgTable, primaryKey, text } from "drizzle-orm/pg-core";
import { drizzle } from "drizzle-orm/vercel-postgres";
export const users = pgTable(
"users",
{
id: text("id").notNull().primaryKey(),
name: text("name"),
email: text("email").notNull(),
emailVerified: timestamp("emailVerified", { mode: "date" }),
image: text("image"),
},
(user) => ({
emailKey: uniqueIndex("User_email_key").on(user.email),
})
);
// const connection = createPool({ connectionString: process.env.POSTGRES_URL });
export const users = pgTable("users", {
id: text("id").notNull().primaryKey(),
name: text("name"),
email: text("email").notNull(),
emailVerified: integer("emailVerified"),
image: text("image"),
});
export const usersRelations = relations(users, ({ many }) => ({
chats: many(chats),
accounts: many(accounts),
}));
export const accounts = pgTable(
"accounts",
@ -41,313 +36,63 @@ export const accounts = pgTable(
id_token: text("id_token"),
session_state: text("session_state"),
},
(table) => {
return {
providerProviderAccountIdKey: uniqueIndex(
"Account_provider_providerAccountId_key"
).on(table.provider, table.providerAccountId),
};
}
(account) => ({
_: primaryKey(account.provider, account.providerAccountId),
})
);
export const sessions = pgTable(
"sessions",
{
sessionToken: text("sessionToken").notNull().primaryKey(),
userId: text("userId")
.notNull()
.references(() => users.id, { onDelete: "cascade" }),
expires: timestamp("expires", { mode: "date" }).notNull(),
},
(table) => {
return {
sessionTokenKey: uniqueIndex("Session_sessionToken_key").on(
table.sessionToken
),
};
}
);
export const sessions = pgTable("sessions", {
userId: text("userId")
.notNull()
.references(() => users.id, { onDelete: "cascade" }),
sessionToken: text("sessionToken").notNull().primaryKey(),
expires: integer("expires").notNull(),
});
export const verificationTokens = pgTable(
"verificationToken",
{
identifier: text("identifier").notNull(),
token: text("token").notNull(),
expires: timestamp("expires", { mode: "date" }).notNull(),
expires: integer("expires").notNull(),
},
(table) => ({
identifierTokenKey: uniqueIndex(
"VerificationToken_identifier_token_key"
).on(table.identifier, table.token),
tokenKey: uniqueIndex("VerificationToken_token_key").on(table.token),
(vt) => ({
_: primaryKey(vt.identifier, vt.token),
})
);
// Connect to Vercel Postgres
export const db = drizzle(sql);
export type DbClient = typeof db;
export type Schema = {
users: typeof users;
accounts: typeof accounts;
sessions: typeof sessions;
verificationTokens: typeof verificationTokens;
};
// import { sql, eq, and } from "drizzle-orm";
// import {
// PgDatabase,
// QueryResultHKT,
// integer,
// pgTable,
// text,
// timestamp,
// uniqueIndex,
// uuid,
// } from "drizzle-orm/pg-core";
// import { drizzle } from "drizzle-orm/vercel-postgres";
// import { sql as c } from "@vercel/postgres";
// import { Adapter, AdapterUser } from "@auth/nextjs/adapters";
// export const db = drizzle(c);
export const chats = pgTable("chats", {
id: text("id").notNull().primaryKey(),
title: text("role").notNull(),
userId: text("userId")
.notNull()
.references(() => users.id),
});
// export const users = pgTable(
// "users",
// {
// id: uuid("id")
// .notNull()
// .primaryKey()
// .default(sql`gen_random_uuid()`),
// name: text("name"),
// email: text("email"),
// emailVerified: timestamp("emailVerified", { precision: 3 }),
// image: text("image"),
// },
// (table) => {
// return {
// emailKey: uniqueIndex("User_email_key").on(table.email),
// };
// }
// );
export const chatsRelations = relations(chats, ({ one }) => ({
user: one(users, {
fields: [chats.userId],
references: [users.id],
}),
}));
// export const verificationTokens = pgTable(
// "verification_tokens",
// {
// identifier: text("identifier").notNull(),
// token: text("token").notNull(),
// expires: timestamp("expires", { precision: 3 }).notNull(),
// },
// (table) => {
// return {
// identifierTokenKey: uniqueIndex(
// "VerificationToken_identifier_token_key"
// ).on(table.identifier, table.token),
// tokenKey: uniqueIndex("VerificationToken_token_key").on(table.token),
// };
// }
// );
export const db = drizzle(sql, {
schema: {
users,
accounts,
sessions,
verificationTokens,
chats,
chatsRelations,
usersRelations,
},
});
// export const sessions = pgTable(
// "sessions",
// {
// id: uuid("id")
// .notNull()
// .primaryKey()
// .default(sql`gen_random_uuid()`),
// sessionToken: text("sessionToken").notNull(),
// userId: uuid("userId")
// .notNull()
// .references(() => users.id, { onDelete: "cascade", onUpdate: "cascade" }),
// expires: timestamp("expires", { precision: 3 }).notNull(),
// },
// (table) => {
// return {
// sessionTokenKey: uniqueIndex("Session_sessionToken_key").on(
// table.sessionToken
// ),
// };
// }
// );
// export const accounts = pgTable(
// "accounts",
// {
// id: uuid("id")
// .notNull()
// .primaryKey()
// .default(sql`gen_random_uuid()`),
// userId: uuid("userId")
// .notNull()
// .references(() => users.id, { onDelete: "cascade", onUpdate: "cascade" }),
// type: text("type").notNull(),
// provider: text("provider").notNull(),
// providerAccountId: text("providerAccountId").notNull(),
// refresh_token: text("refresh_token"),
// access_token: text("access_token"),
// expires_at: integer("expires_at"),
// token_type: text("token_type"),
// scope: text("scope"),
// id_token: text("id_token"),
// session_state: text("session_state"),
// },
// (table) => {
// return {
// providerProviderAccountIdKey: uniqueIndex(
// "Account_provider_providerAccountId_key"
// ).on(table.provider, table.providerAccountId),
// };
// }
// );
// type Users = typeof users;
// type Sessions = typeof sessions;
// type Accounts = typeof accounts;
// type VerificationTokens = typeof verificationTokens;
// export function DrizzleAdapter<
// T extends PgDatabase<U>,
// U extends QueryResultHKT
// >({
// db,
// schema,
// }: {
// db: T;
// schema: {
// users: Users;
// sessions: Sessions;
// accounts: Accounts;
// verificationTokens: VerificationTokens;
// };
// }): Adapter {
// return {
// async createUser(user) {
// const [newUser] = await db.insert(schema.users).values(user).returning();
// return newUser as AdapterUser;
// },
// async getUser(id) {
// const [user] = await db
// .select()
// .from(schema.users)
// .where(eq(schema.users.id, id));
// return (user as AdapterUser) || null;
// },
// async getUserByEmail(email) {
// const [user] = await db
// .select()
// .from(schema.users)
// .where(eq(schema.users.email, email));
// return (user as AdapterUser) || null;
// },
// async getUserByAccount({ providerAccountId, provider }) {
// const results = await db
// .select()
// .from(schema.users)
// .leftJoin(schema.accounts, eq(schema.accounts.userId, schema.users.id))
// .where(
// and(
// eq(schema.accounts.provider, provider),
// eq(schema.accounts.providerAccountId, providerAccountId)
// )
// );
// if (results.length) {
// return results[0].users as AdapterUser;
// }
// return null;
// },
// async updateUser(user) {
// const userId = user.id;
// if (!userId) {
// throw new Error("Cannot update user without id");
// }
// const [updatedUser] = await db
// .update(schema.users)
// .set(user)
// .where(eq(schema.users.id, userId))
// .returning();
// return updatedUser as AdapterUser;
// },
// async deleteUser(userId) {
// await db.delete(schema.users).where(eq(schema.users.id, userId));
// },
// async linkAccount(account) {
// await db.insert(schema.accounts).values(account);
// },
// async unlinkAccount({ providerAccountId, provider }) {
// await db
// .delete(schema.accounts)
// .where(
// and(
// eq(schema.accounts.provider, provider),
// eq(schema.accounts.providerAccountId, providerAccountId)
// )
// );
// },
// async createSession(session) {
// const [newSession] = await db
// .insert(schema.sessions)
// .values(session)
// .returning();
// return newSession;
// },
// async getSessionAndUser(sessionToken) {
// const results = await db
// .select()
// .from(schema.sessions)
// .leftJoin(schema.users, eq(schema.users.id, schema.sessions.userId))
// .where(eq(schema.sessions.sessionToken, sessionToken));
// if (results.length) {
// return {
// user: results[0].users! as AdapterUser,
// session: results[0].sessions,
// };
// }
// return null;
// },
// async updateSession(session) {
// const [updatedSession] = await db
// .update(schema.sessions)
// .set(session)
// .where(eq(schema.sessions.sessionToken, session.sessionToken))
// .returning();
// return updatedSession;
// },
// async deleteSession(sessionToken) {
// await db
// .delete(schema.sessions)
// .where(eq(schema.sessions.sessionToken, sessionToken));
// },
// async createVerificationToken(token) {
// const [newVerificationToken] = await db
// .insert(schema.verificationTokens)
// .values(token)
// .returning();
// return newVerificationToken;
// },
// async useVerificationToken({ identifier, token }) {
// const [deletedVerificationToken] = await db
// .delete(schema.verificationTokens)
// .where(
// and(
// eq(schema.verificationTokens.identifier, identifier),
// eq(schema.verificationTokens.token, token)
// )
// )
// .returning();
// return deletedVerificationToken || null;
// },
// };
// }
export type DbClient = typeof db;