NextAuth.js + Firestore + smtp4devでメールアドレス認証を最速実装
前提
現時点で NextAuth.js は Auth.js への置き換えが進行中です。
その影響だと思われますが、ドキュメント通り実装を進めても一部うまく動作しない部分があったため、Auth.js の @auth/firebase-adapter
は利用しておりません。
また、そのバージョンを明確にするため、この記事執筆時点でのライブラリのバージョンを詳細に記載しています。
経緯
とあるプロジェクトのとある機能を実装する上で、NextAuth.js のメールアドレス認証を使って検証したい内容がありました。
機能実装に向けての検証であったため、とにかくクイックにメールアドレス認証できる環境を構築して検証に入りたかったのですが、なかなか「これさえ見ればOK」というような記事が見当たらなかったため、とにかく最速でメールアドレス認証を実装する方法を書き残しておきます。
利用した主要なライブラリとバージョン
next@13.4.12
next-auth@4.22.3
@next-auth/firebase-adapter@2.0.1
firebase-admin@11.10.1
利用したツール
yarn
smtp4dev
NextAuth.js のテンプレートを利用してプロジェクト作成
まずは NextAuth 公式が提供してくれている、リポジトリテンプレートを利用してプロジェクトを作成します。
作成したプロジェクトをローカルにクローンし、yarn
で依存するパッケージをインストールしておきます。
ここでは、テンプレートを利用してnext-auth-sandbox
というリポジトリを作成した、という前提で記載します。
git clone <テンプレートを利用して作成したリポジトリ>
cd next-auth-sandbox/
yarn
また、テンプレートには最低限必要なパッケージがすでにインストールされていますが、メールアドレス認証やFirestoreとの連携に必要なパッケージはインストールされていません。
なので、ここで必要なパッケージをインストールしておきます。
yarn add nodemailer @next-auth/firebase-adapter firebase-admin
Firestore との連携設定
Firebase プロジェクトの作成
Firebaseプロジェクトを初めて作成される方は、Firebase Consoleで「プロジェクトを作成」、過去に作成したことがある方は「プロジェクトを追加」をクリックします。
プロジェクトの作成手順については、Firebase側でかなり親切なインストラクションがあるので、ここでは細かい手順は割愛します。
手順の中にGoogleアナリティクスを有効にするかどうかの選択がありますが、Firestoreとの連携には不要なのでどちらでもOKです。
Firestore データベースの作成
続けて、Firestore データベースを作成します。
左ペインの Firestore Database
をクリックすると「データベースの作成」ボタンが表示されるのでクリックします。
すると、データベース作成ヘルパーが表示されます。
セキュリティ保護ルールについては「テストモードで開始する」を選択。
Cloud Firestore のロケーション選択は、今回は asia-northeast1 (Tokyo)
を選択。
設定後に変更できない点にだけ注意してください。
ロケーションを選択して「有効にする」をクリックすると Firestore データベースが作成されます。
作成した Firebase プロジェクトを利用するアプリを登録
ここまでで作成した Firebase プロジェクトと、next-auth を連携するためのファイルを準備します。
左ペインの プロジェクトの概要
をクリックしてトップに戻り、「アプリに Firebase を追加して利用を開始しましょう」の下の赤枠のボタンをクリックします。
少々分かりづらいですが、Webアプリと Firebase プロジェクトを連携するためのボタンです。
Firebase 上で連携先のアプリが分かりやすいようにニックネームを設定します。
「このアプリの Firebase Hosting も設定します。」のチェックボックスは、今回の設定には不要なため外したままにしておきます。
「アプリを登録」ボタンをクリックすると、次のステップとして「Firebase SDK の追加」が開きますが、今まさに追加している最中なので、無視して「コンソールに進む」をクリックします。
コンソールに戻ったら、左ペイン「プロジェクトの概要」の右側にある設定アイコンから「プロジェクトの設定」をクリックし、「サービスアカウント」タブを開きます。
タブ内の「新しい秘密鍵を生成」ボタンをクリックし、その後「キーを生成」ボタンをクリック。
Firebase Admin SDK を利用可能にするためのJSONファイルがダウンロードされます。
ダウンロードしたJSONファイルをプロジェクトのルートディレクトリに移動しておきます。また、このタイミングでJSONファイルのリネームもしておきます。
すぐに.gitignore
にも追記して、gitの管理対象外に置きましょう。
mv ~/Downloads/<ダウンロードしたJSONファイル> /path/to/next-auth-sandbox/serviceAccount.json
.DS_Store
node_modules/
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
.yarn-integrity
.npm
.eslintcache
*.tsbuildinfo
next-env.d.ts
.next
.vercel
.env*.local
+ serviceAccount.json
環境変数の設定
テンプレートプロジェクトには.env.local.example
という環境変数設定ファイルのサンプルが用意されています。
これをコピぺして、自分の環境に合わせた環境変数を設定します。
cp .env.local.example .env.local
デフォルトで存在するAUTH0_ID
からTWITTER_SECRET
の環境変数は削除してもしなくてもどちらでも良いです。追加する環境変数は下記のとおりです。
-
EMAIL_SERVER
- SMTPサーバの認証情報とアドレスを設定します。後ほど書きますが、ここでは
smtp4dev
を利用するので認証情報は空でOK
- SMTPサーバの認証情報とアドレスを設定します。後ほど書きますが、ここでは
-
EMAIL_FROM
- どんなアドレスからメールが届くようにするかを設定します。仮で
noreply@example.com
としています。
- どんなアドレスからメールが届くようにするかを設定します。仮で
-
GOOGLE_APPLICATION_CREDENTIALS
- 先ほど作成した Firebase Admin SDK の認証情報ファイルへのパスを設定します。これでFirebase Admin SDK が自動で認証情報を読み込んでくれます。
NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_SECRET= # Linux: `openssl rand -hex 32` or go to https://generate-secret.now.sh/32
-AUTH0_ID=
-AUTH0_SECRET=
-AUTH0_ISSUER=
-
-DESCOPE_ID=
-DESCOPE_SECRET=
-
-FACEBOOK_ID=
-FACEBOOK_SECRET=
-
-GITHUB_ID=
-GITHUB_SECRET=
-
-GOOGLE_ID=
-GOOGLE_SECRET=
-
-TWITTER_ID=
-TWITTER_SECRET=
-
+EMAIL_SERVER=smtp://"":""@localhost:2525
+EMAIL_FROM=noreply@example.com
+
+GOOGLE_APPLICATION_CREDENTIALS=./serviceAccount.json
+
実装
これでようやく設定が完了したのでコードを修正していきます。一瞬です。
テンプレートのコードを修正してメール認証、Firestoreとの連携部分を設定します。
import NextAuth, { NextAuthOptions } from "next-auth"
- import GoogleProvider from "next-auth/providers/google"
- import FacebookProvider from "next-auth/providers/facebook"
- import GithubProvider from "next-auth/providers/github"
- import TwitterProvider from "next-auth/providers/twitter"
- import Auth0Provider from "next-auth/providers/auth0"
+ import EmailProvider from "next-auth/providers/email"
+ import { FirestoreAdapter } from "@next-auth/firebase-adapter";
// For more information on each option (and a full list of options) go to
// https://next-auth.js.org/configuration/options
export const authOptions: NextAuthOptions = {
// https://next-auth.js.org/configuration/providers/oauth
+ adapter: FirestoreAdapter(),
providers: [
- Auth0Provider({
- clientId: process.env.AUTH0_ID,
- clientSecret: process.env.AUTH0_SECRET,
- issuer: process.env.AUTH0_ISSUER,
- }),
- FacebookProvider({
- clientId: process.env.FACEBOOK_ID,
- clientSecret: process.env.FACEBOOK_SECRET,
- }),
- GithubProvider({
- clientId: process.env.GITHUB_ID,
- clientSecret: process.env.GITHUB_SECRET,
- }),
- GoogleProvider({
- clientId: process.env.GOOGLE_ID,
- clientSecret: process.env.GOOGLE_SECRET,
- }),
- TwitterProvider({
- clientId: process.env.TWITTER_ID,
- clientSecret: process.env.TWITTER_SECRET,
- version: "2.0",
- }),
+ EmailProvider({
+ server: process.env.EMAIL_SERVER,
+ from: process.env.EMAIL_FROM
+ }),
],
callbacks: {
async jwt({ token }) {
token.userRole = "admin"
return token
},
},
}
export default NextAuth(authOptions)
動作確認
smtp4dev
の起動
SMTPサーバがないとメールが送られたことの確認ができないので、ローカルにダミーのSMTPサーバを立てます。
dockerが利用できる場合は、dockerでsmtp4dev
を起動するのが一番簡単で速いです。
next.jsが3000番ポートで起動するので、smtp4dev
は3001番ポートでアクセスできるようにします。
docker run --rm -it -p 3001:80 -p 2525:25 rnwood/smtp4dev
next-auth サンプルアプリケーションの起動
別ターミナルを開き、yarn dev
でサンプルアプリケーションを起動します。
「Sign in」ボタンをクリックすると、メールログイン画面に遷移します。
メールアドレスを入力し、「Sign in with Email」ボタンをクリックします。
この時、メールが実際に送信されるわけではないのでアドレスは仮のものでもOKです。
すると、メールをチェックしてねという画面に切り替わります。
どこにメールが送信されているかというと、smtp4dev
で送信されたメールが確認できます。
http://localhost:3001
にアクセスするとsmtp4dev
で受信ボックスのようなUIが構築されており、1件メールが届いていることが分かると思います。
これが next-auth からの認証メールです。
メール内の「Sign in」ボタンをクリックすると next-auth のサンプルアプリケーションに戻り、先ほど入力したメールアドレスのユーザとして認証されている旨の表示がされます。
参考にさせていただいたサイト
Discussion