После долгого поиска документации по этой проблеме, наконец, я решил написать этот пост, чтобы помочь разработчикам, оказавшимся в такой же ситуации.

Адаптер Mongodb — это утилита, которая предоставляет нам «метод» для сохранения пользователей/учетных записей/сеансов в Mongodb с использованием таких поставщиков, как Google, Github и т. д. Но что произойдет, если вы захотите сохранить свои пользовательские данные в mongodb?

Сначала я использовал пакет mongoose для управления им, но nextauth дает нам реализацию, которая ускоряет процесс, не прибегая к другим внешним библиотекам, таким как mongoose. Нам просто нужно использовать MongoClient и написать небольшую утилиту, чтобы поддерживать связь.

Настройте наш адаптер

npm install next-auth @next-auth/mongodb-adapter mongodb

Как говорится в документации, адаптер Mongodb не обрабатывает соединения автоматически, поэтому нам нужно передать клиентское подключение к адаптеру.

Адаптер MongoDB не обрабатывает соединения автоматически, поэтому вам нужно убедиться, что вы передаете адаптеру MongoClient, который уже подключен. Ниже вы можете увидеть пример, как это сделать.

https://authjs.dev/reference/adapter/mongodb

Клиент MongoDB

// This approach is taken from https://github.com/vercel/next.js/tree/canary/examples/with-mongodb
import { MongoClient } from "mongodb";

if (!process.env.MONGODB_URI) {
  throw new Error('Invalid/Missing environment variable: "MONGODB_URI"');
}

const uri = process.env.MONGODB_URI;
const options = {};

let client;
let clientPromise: Promise<MongoClient>;

if (process.env.NODE_ENV === "development") {
  // In development mode, use a global variable so that the value
  // is preserved across module reloads caused by HMR (Hot Module Replacement).
  if (!global._mongoClientPromise) {
    client = new MongoClient(uri, options);
    global._mongoClientPromise = client.connect();
  }
  clientPromise = global._mongoClientPromise;
} else {
  // In production mode, it's best to not use a global variable.
  client = new MongoClient(uri, options);
  clientPromise = client.connect();
}

// Export a module-scoped MongoClient promise. By doing this in a
// separate module, the client can be shared across functions.
export default clientPromise;

Не забудьте создать переменную среды в файле .env с uri mongodb.

Учетные данные и обратные вызовы

Вы можете использовать методы, предоставляемые адаптером next-auth, чтобы найти своего пользователя, например, getUserByEmail (ваш «[email protected]»). И, конечно же, вы можете взять это письмо из учетных данных, getUserByEmail(credentials.username)

import clientPromise from "@/app/lib/mongodb";
import { MongoDBAdapter } from "@next-auth/mongodb-adapter";
import NextAuth from "next-auth";
import CredentialsProvider from "next-auth/providers/credentials";
import GitHubProvider from "next-auth/providers/github";

export const authOptions = {
  adapter: MongoDBAdapter(clientPromise),
  providers: [
    GitHubProvider({
      clientId: process.env.GITHUB_ID,
      clientSecret: process.env.GITHUB_SECRET,
    }),
    CredentialsProvider({
      name: "credentials",
      credentials: {
        username: { label: "Username", type: "text", placeholder: "Aaron" },
        password: { label: "Password", type: "password" },
      },
      async authorize(credentials, req) {
        // Find your user in the database using MongoDBAdapter
        const user = await authOptions.adapter.getUser(
          "6471f710f772cf139bc5142e"
        );
        if (user) {
          return user;
        } else {
          return null;
        }
      },
    }),
  ],
  secret: process.env.NEXTAUTH_SECRET,
  session: {
    // Set it as jwt instead of database
    strategy: "jwt",
  },
  callbacks: {
    async jwt({ token, user }) {
      // Persist the OAuth access_token and or the user id to the token right after signin
      if (user) {
        token.accessToken = user.access_token;
        token.id = user.id;
      }
      return token;
    },
    async session({ session, token }) {
      // Send properties to the client, like an access_token and user id from a provider.
      session.accessToken = token.accessToken;
      session.user.id = token.id;

      return session;
    },
  },
};

const handler = NextAuth(authOptions);

export { handler as GET, handler as POST };

Обратите внимание: если вы хотите сохранить сеанс учетных данных, вам нужно установить session.strategy как «jwt». Поставщик учетных данных не сохраняет сеанс в базе данных.

Поставщик учетных данных можно использовать только в том случае, если для сеансов включены веб-токены JSON. Пользователи, прошедшие проверку подлинности с помощью поставщика учетных данных, не сохраняются в базе данных.

https://next-auth.js.org/configuration/providers/credentials

Даже вы можете сохранить пользовательские данные в сеансе пользователя. Просто передайте дополнительные параметры в обратный вызов сеанса.

Провайдер сеанса

Не забудьте обернуть layout.js компонентом SessionProvider, чтобы получить доступ пользователя ко всему приложению.

"use client";
import { SessionProvider } from "next-auth/react";
import "./globals.css";

export const metadata = {
  title: "Create Next App",
  description: "Generated by create next app",
};

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <SessionProvider>
        <body>{children}</body>
      </SessionProvider>
    </html>
  );
}

Теперь вы можете получить доступ к URL-адресу https://localhost:3000/api/auth/signin/credentials и войти, используя свои учетные данные или через своего провайдера.

После этого у вас должен быть доступ к сессии и ее свойствам с помощью хука useSession.

А из бэкенда с помощью getServerSession.

import { authOptions } from "../auth/[...nextauth]/route";
import { getServerSession } from "next-auth";

export async function GET(Request) {
  const session = await getServerSession(authOptions);

  if (session) {
    return new Response(JSON.stringify(session), { status: 200 });
  } else {
    return new Response("Not authenticated user!", { status: 401 });
  }
}

Ссылки

Github: https://github.com/aaronaira/next-auth-example-mongodbadapter

Linkedin: https://www.linkedin.com/in/aaron-aira/