UNPKG

@auth/prisma-adapter

Version:
134 lines (131 loc) 4.52 kB
/** * <div style={{display: "flex", justifyContent: "space-between", alignItems: "center", padding: 16}}> * Official <a href="https://www.prisma.io/docs">Prisma</a> adapter for Auth.js / NextAuth.js. * <a href="https://www.prisma.io/"> * <img style={{display: "block"}} src="https://authjs.dev/img/adapters/prisma.svg" width="38" /> * </a> * </div> * * ## Installation * * ```bash npm2yarn * npm install @prisma/client @auth/prisma-adapter * npm install prisma --save-dev * ``` * * @module @auth/prisma-adapter */ import type { PrismaClient } from "@prisma/client" import type { Adapter, AdapterAccount, AdapterSession, AdapterUser, } from "@auth/core/adapters" export function PrismaAdapter( prisma: PrismaClient | ReturnType<PrismaClient["$extends"]> ): Adapter { const p = prisma as PrismaClient return { // We need to let Prisma generate the ID because our default UUID is incompatible with MongoDB createUser: ({ id, ...data }) => p.user.create(stripUndefined(data)), getUser: (id) => p.user.findUnique({ where: { id } }), getUserByEmail: (email) => p.user.findUnique({ where: { email } }), async getUserByAccount(provider_providerAccountId) { const account = await p.account.findUnique({ where: { provider_providerAccountId }, include: { user: true }, }) return (account?.user as AdapterUser) ?? null }, updateUser: ({ id, ...data }) => p.user.update({ where: { id }, ...stripUndefined(data), }) as Promise<AdapterUser>, deleteUser: (id) => p.user.delete({ where: { id } }) as Promise<AdapterUser>, linkAccount: (data) => p.account.create({ data }) as unknown as AdapterAccount, unlinkAccount: (provider_providerAccountId) => p.account.delete({ where: { provider_providerAccountId }, }) as unknown as AdapterAccount, async getSessionAndUser(sessionToken) { const userAndSession = await p.session.findUnique({ where: { sessionToken }, include: { user: true }, }) if (!userAndSession) return null const { user, ...session } = userAndSession return { user, session } as { user: AdapterUser; session: AdapterSession } }, createSession: (data) => p.session.create(stripUndefined(data)), updateSession: (data) => p.session.update({ where: { sessionToken: data.sessionToken }, ...stripUndefined(data), }), deleteSession: (sessionToken) => p.session.delete({ where: { sessionToken } }), async createVerificationToken(data) { const verificationToken = await p.verificationToken.create( stripUndefined(data) ) if ("id" in verificationToken && verificationToken.id) delete verificationToken.id return verificationToken }, async useVerificationToken(identifier_token) { try { const verificationToken = await p.verificationToken.delete({ where: { identifier_token }, }) if ("id" in verificationToken && verificationToken.id) delete verificationToken.id return verificationToken } catch (error: unknown) { // If token already used/deleted, just return null // https://www.prisma.io/docs/reference/api-reference/error-reference#p2025 if ( error && typeof error === "object" && "code" in error && error.code === "P2025" ) return null throw error } }, async getAccount(providerAccountId, provider) { return p.account.findFirst({ where: { providerAccountId, provider }, }) as Promise<AdapterAccount | null> }, async createAuthenticator(data) { return p.authenticator.create(stripUndefined(data)) }, async getAuthenticator(credentialID) { return p.authenticator.findUnique({ where: { credentialID }, }) }, async listAuthenticatorsByUserId(userId) { return p.authenticator.findMany({ where: { userId }, }) }, async updateAuthenticatorCounter(credentialID, counter) { return p.authenticator.update({ where: { credentialID }, data: { counter }, }) }, } } /** @see https://www.prisma.io/docs/orm/prisma-client/special-fields-and-types/null-and-undefined */ function stripUndefined<T>(obj: T) { const data = {} as T for (const key in obj) if (obj[key] !== undefined) data[key] = obj[key] return { data } }