WebAuthn (パスキー)
WebAuthn / パスキープロバイダーは実験的であり、本番環境での使用は推奨されません。
WebAuthn プロバイダーは、フレームワーク統合と、それをサポートする予定のすべてのデータベースアダプターの変更が必要です。したがって、WebAuthn プロバイダーは現在、以下のフレームワーク統合とデータベースアダプターでのみサポートされています。より多くのフレームワークとアダプターのサポートは近日中に提供予定です。
next-auth@5.0.0-beta.8
以上@auth/prisma-adapter@1.3.0
以上node@20.0.0
以上
ピア依存関係をインストール
npm install @simplewebauthn/server@9.0.3 @simplewebauthn/browser@9.0.1
@simplewebauthn/browser
ピア依存関係は、**カスタムサインインページでのみ必要**です。Auth.js のデフォルトページを使用している場合は、そのピア依存関係のインストールをスキップできます。
必要なスキーマ移行を適用
これは PostgreSQL の生の SQL マイグレーションです。他のデータベースの移行例を含む詳細については、@auth/prisma-adapter
ドキュメントの更新された Prisma スキーマを確認してください。
要するに、パスキープロバイダーは Authenticator
という追加のテーブルが必要です。
-- CreateTable
CREATE TABLE "Authenticator" (
"credentialID" TEXT NOT NULL,
"userId" TEXT NOT NULL,
"providerAccountId" TEXT NOT NULL,
"credentialPublicKey" TEXT NOT NULL,
"counter" INTEGER NOT NULL,
"credentialDeviceType" TEXT NOT NULL,
"credentialBackedUp" BOOLEAN NOT NULL,
"transports" TEXT,
PRIMARY KEY ("userId", "credentialID"),
CONSTRAINT "Authenticator_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE CASCADE ON UPDATE CASCADE
);
-- CreateIndex
CREATE UNIQUE INDEX "Authenticator_credentialID_key" ON "Authenticator"("credentialID");
Auth.js の構成を更新
構成に Passkeys
プロバイダーを追加します。また、互換性のあるデータベースアダプターを使用していることを確認してください。
import Passkey from "next-auth/providers/passkey"
import { PrismaAdapter } from "@auth/prisma-adapter"
import { PrismaClient } from "@prisma/client"
const prisma = new PrismaClient()
export default {
adapter: PrismaAdapter(prisma),
providers: [Passkey],
experimental: { enableWebAuthn: true },
}
組み込みの Auth.js ページを使用している場合は、準備完了です!/signin
ルートに移動すると、「パスキーでサインイン」ボタンが含まれているはずです。
カスタムページ
カスタムサインインページを使用している場合は、next-auth
signIn
関数を利用して、次のコードで WebAuthn の登録とログインフローを開始できます。
WebAuthn signIn
関数を使用する場合は、@simplewebauth/browser
ピア依存関係もインストールする必要があります。
"use client"
import { useSession } from "next-auth/react"
import { signIn } from "next-auth/webauthn"
export default function Login() {
const { data: session, update, status } = useSession()
return (
<div>
{status === "authenticated" ? (
<button onClick={() => signIn("passkey", { action: "register" })}>
Register new Passkey
</button>
) : status === "unauthenticated" ? (
<button onClick={() => signIn("passkey")}>Sign in with Passkey</button>
) : null}
</div>
)
}