Skip to content

Instantly share code, notes, and snippets.

@adriangalilea
Created March 18, 2024 20:54
Show Gist options
  • Save adriangalilea/6601f0fcde1a2225977054d79d2a0d4e to your computer and use it in GitHub Desktop.
Save adriangalilea/6601f0fcde1a2225977054d79d2a0d4e to your computer and use it in GitHub Desktop.
NextAuth Auth.js module augmentation + custom adapter
import NextAuth from "next-auth";
import GitHub from "next-auth/providers/github";
import { DrizzleAdapter } from "@auth/drizzle-adapter";
import { db } from "./db";
import { type AdapterUser, Adapter } from "@auth/core/adapters";
import { users, accounts, verificationTokens, sessions } from "@/db/schema";
import { eq, and } from "drizzle-orm";
declare module "next-auth" {
interface Profile {
gh_id: string;
gh_image: string;
gh_username: string;
}
interface User {
gh_id: string;
gh_image: string;
gh_username: string;
}
}
function customAdapter(): Adapter {
const adapter = DrizzleAdapter(db);
// Overwrite createUser method on adapter
adapter.createUser = async (data): Promise<AdapterUser> => {
// console.log("Creating user", data);
const dataEntered = await db
.insert(users)
.values({
...data,
id: crypto.randomUUID(),
// @ts-ignore
gh_id: data.gh_id,
// @ts-ignore
gh_username: data.gh_username,
// @ts-ignore
gh_image: data.gh_image,
})
.returning()
.then((res) => res[0] ?? null);
if (!dataEntered) {
throw new Error("User Creation Failed");
}
// @ts-ignore
return dataEntered;
};
// @ts-ignore
adapter.getUser = async (data) => {
console.log("Getting user", data);
const result = await db
.select()
.from(users)
.where(eq(users.id, data))
.get();
return result ?? null;
};
// @ts-ignore
adapter.getUserByEmail = async (data) => {
console.log("Getting user by email", data);
const result = await db
.select()
.from(users)
.where(eq(users.email, data))
.get();
return result ?? null;
};
// @ts-ignore
adapter.createSession = (data) => {
console.log("Creating session", data);
return db.insert(sessions).values(data).returning().get();
};
// @ts-ignore
adapter.getSessionAndUser = async (data) => {
console.log("Getting session and user", data);
const result = await db
.select({ session: sessions, user: users })
.from(sessions)
.where(eq(sessions.sessionToken, data))
.innerJoin(users, eq(users.id, sessions.userId))
.get();
return result ?? null;
};
// @ts-ignore
adapter.updateUser = async (data) => {
if (!data.id) {
throw new Error("No user id.");
}
const result = await db
.update(users)
.set(data)
.where(eq(users.id, data.id))
.returning()
.get();
return result ?? null;
};
// @ts-ignore
adapter.updateSession = async (data) => {
const result = await db
.update(sessions)
.set(data)
.where(eq(sessions.sessionToken, data.sessionToken))
.returning()
.get();
return result ?? null;
};
// @ts-ignore
adapter.getUserByAccount = async (account) => {
console.log("Getting user by account", account);
const results = await db
.select()
.from(accounts)
.leftJoin(users, eq(users.id, accounts.userId))
.where(
and(
eq(accounts.provider, account.provider),
eq(accounts.providerAccountId, account.providerAccountId)
)
)
.get();
if (!results) {
return null;
}
return Promise.resolve(results).then((results) => results.user);
};
// @ts-ignore
adapter.deleteSession = async (sessionToken) => {
const result = await db
.delete(sessions)
.where(eq(sessions.sessionToken, sessionToken))
.returning()
.get();
return result ?? null;
};
// @ts-ignore
adapter.createVerificationToken = async (token) => {
const result = await db
.insert(verificationTokens)
.values(token)
.returning()
.get();
return result ?? null;
};
// @ts-ignore
adapter.useVerificationToken = async (token) => {
try {
const result = await db
.delete(verificationTokens)
.where(
and(
eq(verificationTokens.identifier, token.identifier),
eq(verificationTokens.token, token.token)
)
)
.returning()
.get();
return result ?? null;
} catch (err) {
throw new Error("No verification token found.");
}
};
// @ts-ignore
adapter.deleteUser = async (id) => {
const result = await db
.delete(users)
.where(eq(users.id, id))
.returning()
.get();
return result ?? null;
};
// @ts-ignore
adapter.unlinkAccount = async (account) => {
await db
.delete(accounts)
.where(
and(
eq(accounts.providerAccountId, account.providerAccountId),
eq(accounts.provider, account.provider)
)
)
.run();
};
return {
...adapter,
};
}
export const {
handlers: { GET, POST },
auth,
signIn,
signOut,
} = NextAuth({
debug: true,
basePath: "/auth",
adapter: customAdapter(),
providers: [
GitHub({
profile(profile) {
return {
id: profile.id.toString(),
gh_id: profile.id.toString(),
name: profile.name ?? profile.login,
email: profile.email,
gh_image: profile.avatar_url,
gh_username: profile.login,
};
},
}),
],
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment