コンテンツへスキップ
NextAuth.js v4 からの移行ですか? 移行ガイドをご覧ください.
はじめに認証認証情報

認証情報

Auth.jsを外部認証メカニズムでセットアップしたり、従来のユーザー名/メールとパスワードのフローを使用したりするには、Credentials プロバイダーを使用できます。このプロバイダーは、ログインフォームに入力された認証情報(ユーザー名/パスワードに限らない)を認証サービスに転送するように設計されています。

⚠️

業界は、ウェブアプリケーションのユーザー認証と認可のメカニズムとして、ユーザー名とパスワードを用いる方法から大きく進歩してきました。そのため、可能な限り、OAuth プロバイダーメールマジックリンク、またはWebAuthn (パスキー)オプションのような、よりモダンで安全な認証メカニズムをお勧めします。

しかし、私たちは柔軟であり、アプリケーションやユースケースに適したものをサポートしたいと考えているため、このプロバイダーを削除する予定はありません。

💡

デフォルトでは、Credentialsプロバイダーはデータベースにデータを永続化しません。ただし、データベースでデータを引き続き作成および保存できます。パスワードの暗号化、レート制限の追加、パスワードリセット機能の追加など、必要なロジックを提供するだけです。

Credentialsプロバイダー

まず、Auth.jsの設定ファイルでCredentialsプロバイダーを初期化しましょう。プロバイダーをインポートし、providers配列に追加する必要があります。

./auth.ts
import NextAuth from "next-auth"
import Credentials from "next-auth/providers/credentials"
// Your own logic for dealing with plaintext password strings; be careful!
import { saltAndHashPassword } from "@/utils/password"
 
export const { handlers, signIn, signOut, auth } = NextAuth({
  providers: [
    Credentials({
      // You can specify which fields should be submitted, by adding keys to the `credentials` object.
      // e.g. domain, username, password, 2FA token, etc.
      credentials: {
        email: {},
        password: {},
      },
      authorize: async (credentials) => {
        let user = null
 
        // logic to salt and hash password
        const pwHash = saltAndHashPassword(credentials.password)
 
        // logic to verify if the user exists
        user = await getUserFromDb(credentials.email, pwHash)
 
        if (!user) {
          // No user found, so this is their first attempt to login
          // Optionally, this is also the place you could do a user registration
          throw new Error("Invalid credentials.")
        }
 
        // return user object with their profile data
        return user
      },
    }),
  ],
})

TypeScriptを使用している場合は、Userインターフェースを拡張して、authorizeコールバックのレスポンスと一致させることができます。これにより、他のコールバック(jwtなど)でユーザーを読み取るたびに、型が正しく一致します。

サインインフォーム

最後に、簡単なサインインフォームを作成しましょう。

./components/sign-in.tsx
import { signIn } from "@/auth"
 
export function SignIn() {
  return (
    <form
      action={async (formData) => {
        "use server"
        await signIn("credentials", formData)
      }}
    >
      <label>
        Email
        <input name="email" type="email" />
      </label>
      <label>
        Password
        <input name="password" type="password" />
      </label>
      <button>Sign In</button>
    </form>
  )
}

認証情報の検証

常にサーバー側で認証情報を検証してください。つまり、Zodのようなスキーマ検証ライブラリを活用します。

npm install zod

次に、Credentialsプロバイダーのauthorizeコールバックを使用して、auth.ts設定ファイルでスキーマと解析を設定します。

./lib/zod.ts
import { object, string } from "zod"
 
export const signInSchema = object({
  email: string({ required_error: "Email is required" })
    .min(1, "Email is required")
    .email("Invalid email"),
  password: string({ required_error: "Password is required" })
    .min(1, "Password is required")
    .min(8, "Password must be more than 8 characters")
    .max(32, "Password must be less than 32 characters"),
})
./auth.ts
import NextAuth from "next-auth"
import { ZodError } from "zod"
import Credentials from "next-auth/providers/credentials"
import { signInSchema } from "./lib/zod"
// Your own logic for dealing with plaintext password strings; be careful!
import { saltAndHashPassword } from "@/utils/password"
import { getUserFromDb } from "@/utils/db"
 
export const { handlers, auth } = NextAuth({
  providers: [
    Credentials({
      // You can specify which fields should be submitted, by adding keys to the `credentials` object.
      // e.g. domain, username, password, 2FA token, etc.
      credentials: {
        email: {},
        password: {},
      },
      authorize: async (credentials) => {
        try {
          let user = null
 
          const { email, password } = await signInSchema.parseAsync(credentials)
 
          // logic to salt and hash password
          const pwHash = saltAndHashPassword(password)
 
          // logic to verify if the user exists
          user = await getUserFromDb(email, pwHash)
 
          if (!user) {
            throw new Error("Invalid credentials.")
          }
 
          // return JSON object with the user data
          return user
        } catch (error) {
          if (error instanceof ZodError) {
            // Return `null` to indicate that the credentials are invalid
            return null
          }
        }
      },
    }),
  ],
})
Auth.js © Balázs Orbán and Team -2024