264 lines
9.3 KiB
JavaScript
264 lines
9.3 KiB
JavaScript
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.PrismaAdapter = void 0;
|
|
/**
|
|
* ## Setup
|
|
*
|
|
* Add this adapter to your `pages/api/[...nextauth].js` next-auth configuration object:
|
|
*
|
|
* ```js title="pages/api/auth/[...nextauth].js"
|
|
* import NextAuth from "next-auth"
|
|
* import GoogleProvider from "next-auth/providers/google"
|
|
* import { PrismaAdapter } from "@next-auth/prisma-adapter"
|
|
* import { PrismaClient } from "@prisma/client"
|
|
*
|
|
* const prisma = new PrismaClient()
|
|
*
|
|
* export default NextAuth({
|
|
* adapter: PrismaAdapter(prisma),
|
|
* providers: [
|
|
* GoogleProvider({
|
|
* clientId: process.env.GOOGLE_CLIENT_ID,
|
|
* clientSecret: process.env.GOOGLE_CLIENT_SECRET,
|
|
* }),
|
|
* ],
|
|
* })
|
|
* ```
|
|
*
|
|
* ### Create the Prisma schema from scratch
|
|
*
|
|
* You need to use at least Prisma 2.26.0. Create a schema file in `prisma/schema.prisma` similar to this one:
|
|
*
|
|
* > This schema is adapted for use in Prisma and based upon our main [schema](https://authjs.dev/reference/adapters#models)
|
|
*
|
|
* ```json title="schema.prisma"
|
|
* datasource db {
|
|
* provider = "postgresql"
|
|
* url = env("DATABASE_URL")
|
|
* shadowDatabaseUrl = env("SHADOW_DATABASE_URL") // Only needed when using a cloud provider that doesn't support the creation of new databases, like Heroku. Learn more: https://pris.ly/d/migrate-shadow
|
|
* }
|
|
*
|
|
* generator client {
|
|
* provider = "prisma-client-js"
|
|
* previewFeatures = ["referentialActions"] // You won't need this in Prisma 3.X or higher.
|
|
* }
|
|
*
|
|
* model Account {
|
|
* id String @id @default(cuid())
|
|
* userId String
|
|
* type String
|
|
* provider String
|
|
* providerAccountId String
|
|
* refresh_token String? @db.Text
|
|
* access_token String? @db.Text
|
|
* expires_at Int?
|
|
* token_type String?
|
|
* scope String?
|
|
* id_token String? @db.Text
|
|
* session_state String?
|
|
*
|
|
* user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
*
|
|
* @@unique([provider, providerAccountId])
|
|
* }
|
|
*
|
|
* model Session {
|
|
* id String @id @default(cuid())
|
|
* sessionToken String @unique
|
|
* userId String
|
|
* expires DateTime
|
|
* user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
* }
|
|
*
|
|
* model User {
|
|
* id String @id @default(cuid())
|
|
* name String?
|
|
* email String? @unique
|
|
* emailVerified DateTime?
|
|
* image String?
|
|
* accounts Account[]
|
|
* sessions Session[]
|
|
* }
|
|
*
|
|
* model VerificationToken {
|
|
* identifier String
|
|
* token String @unique
|
|
* expires DateTime
|
|
*
|
|
* @@unique([identifier, token])
|
|
* }
|
|
* ```
|
|
*
|
|
* :::note
|
|
* When using the MySQL connector for Prisma, the [Prisma `String` type](https://www.prisma.io/docs/reference/api-reference/prisma-schema-reference#string) gets mapped to `varchar(191)` which may not be long enough to store fields such as `id_token` in the `Account` model. This can be avoided by explicitly using the `Text` type with `@db.Text`.
|
|
* :::
|
|
*
|
|
*
|
|
* ### Create the Prisma schema with `prisma migrate`
|
|
*
|
|
* This will create an SQL migration file and execute it:
|
|
*
|
|
* ```
|
|
* npx prisma migrate dev
|
|
* ```
|
|
*
|
|
* Note that you will need to specify your database connection string in the environment variable `DATABASE_URL`. You can do this by setting it in a `.env` file at the root of your project.
|
|
*
|
|
* To learn more about [Prisma Migrate](https://www.prisma.io/migrate), check out the [Migrate docs](https://www.prisma.io/docs/concepts/components/prisma-migrate).
|
|
*
|
|
* ### Generating the Prisma Client
|
|
*
|
|
* Once you have saved your schema, use the Prisma CLI to generate the Prisma Client:
|
|
*
|
|
* ```
|
|
* npx prisma generate
|
|
* ```
|
|
*
|
|
* To configure your database to use the new schema (i.e. create tables and columns) use the `prisma migrate` command:
|
|
*
|
|
* ```
|
|
* npx prisma migrate dev
|
|
* ```
|
|
*
|
|
* ### MongoDB support
|
|
*
|
|
* Prisma supports MongoDB, and so does Auth.js. Following the instructions of the [Prisma documentation](https://www.prisma.io/docs/concepts/database-connectors/mongodb) on the MongoDB connector, things you have to change are:
|
|
*
|
|
* 1. Make sure that the id fields are mapped correctly
|
|
*
|
|
* ```prisma
|
|
* id String @id @default(auto()) @map("_id") @db.ObjectId
|
|
* ```
|
|
*
|
|
* 2. The Native database type attribute to `@db.String` from `@db.Text` and userId to `@db.ObjectId`.
|
|
*
|
|
* ```prisma
|
|
* user_id String @db.ObjectId
|
|
* refresh_token String? @db.String
|
|
* access_token String? @db.String
|
|
* id_token String? @db.String
|
|
* ```
|
|
*
|
|
* Everything else should be the same.
|
|
*
|
|
* ### Naming Conventions
|
|
*
|
|
* If mixed snake_case and camelCase column names is an issue for you and/or your underlying database system, we recommend using Prisma's `@map()`([see the documentation here](https://www.prisma.io/docs/concepts/components/prisma-schema/names-in-underlying-database)) feature to change the field names. This won't affect Auth.js, but will allow you to customize the column names to whichever naming convention you wish.
|
|
*
|
|
* For example, moving to `snake_case` and plural table names.
|
|
*
|
|
* ```json title="schema.prisma"
|
|
* model Account {
|
|
* id String @id @default(cuid())
|
|
* userId String @map("user_id")
|
|
* type String
|
|
* provider String
|
|
* providerAccountId String @map("provider_account_id")
|
|
* refresh_token String? @db.Text
|
|
* access_token String? @db.Text
|
|
* expires_at Int?
|
|
* token_type String?
|
|
* scope String?
|
|
* id_token String? @db.Text
|
|
* session_state String?
|
|
*
|
|
* user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
*
|
|
* @@unique([provider, providerAccountId])
|
|
* @@map("accounts")
|
|
* }
|
|
*
|
|
* model Session {
|
|
* id String @id @default(cuid())
|
|
* sessionToken String @unique @map("session_token")
|
|
* userId String @map("user_id")
|
|
* expires DateTime
|
|
* user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
*
|
|
* @@map("sessions")
|
|
* }
|
|
*
|
|
* model User {
|
|
* id String @id @default(cuid())
|
|
* name String?
|
|
* email String? @unique
|
|
* emailVerified DateTime? @map("email_verified")
|
|
* image String?
|
|
* accounts Account[]
|
|
* sessions Session[]
|
|
*
|
|
* @@map("users")
|
|
* }
|
|
*
|
|
* model VerificationToken {
|
|
* identifier String
|
|
* token String @unique
|
|
* expires DateTime
|
|
*
|
|
* @@unique([identifier, token])
|
|
* @@map("verificationtokens")
|
|
* }
|
|
* ```
|
|
*
|
|
**/
|
|
function PrismaAdapter(p) {
|
|
return {
|
|
createUser: (data) => p.user.create({ data }),
|
|
getUser: (id) => p.user.findUnique({ where: { id } }),
|
|
getUserByEmail: (email) => p.user.findUnique({ where: { email } }),
|
|
async getUserByAccount(provider_providerAccountId) {
|
|
var _a;
|
|
const account = await p.account.findUnique({
|
|
where: { provider_providerAccountId },
|
|
select: { user: true },
|
|
});
|
|
return (_a = account === null || account === void 0 ? void 0 : account.user) !== null && _a !== void 0 ? _a : null;
|
|
},
|
|
updateUser: ({ id, ...data }) => p.user.update({ where: { id }, data }),
|
|
deleteUser: (id) => p.user.delete({ where: { id } }),
|
|
linkAccount: (data) => p.account.create({ data }),
|
|
unlinkAccount: (provider_providerAccountId) => p.account.delete({
|
|
where: { provider_providerAccountId },
|
|
}),
|
|
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 };
|
|
},
|
|
createSession: (data) => p.session.create({ data }),
|
|
updateSession: (data) => p.session.update({ where: { sessionToken: data.sessionToken }, data }),
|
|
deleteSession: (sessionToken) => p.session.delete({ where: { sessionToken } }),
|
|
async createVerificationToken(data) {
|
|
const verificationToken = await p.verificationToken.create({ data });
|
|
// @ts-expect-errors // MongoDB needs an ID, but we don't
|
|
if (verificationToken.id)
|
|
delete verificationToken.id;
|
|
return verificationToken;
|
|
},
|
|
async useVerificationToken(identifier_token) {
|
|
try {
|
|
const verificationToken = await p.verificationToken.delete({
|
|
where: { identifier_token },
|
|
});
|
|
// @ts-expect-errors // MongoDB needs an ID, but we don't
|
|
if (verificationToken.id)
|
|
delete verificationToken.id;
|
|
return verificationToken;
|
|
}
|
|
catch (error) {
|
|
// If token already used/deleted, just return null
|
|
// https://www.prisma.io/docs/reference/api-reference/error-reference#p2025
|
|
if (error.code === "P2025")
|
|
return null;
|
|
throw error;
|
|
}
|
|
},
|
|
};
|
|
}
|
|
exports.PrismaAdapter = PrismaAdapter;
|