Next.js + NextAuthでメールアドレス/パスワード認証をする
NextAuth は Next.js に簡単に認証機能を追加できるライブラリです。TwitterやGoogleといった有名サービスのOAuth認証や、パスワードが不要なメールリンク認証などを簡単に組み込むことができます。
NextAuth はパスワードレス(パスワードなし)の認証を推進しているため、従来のようなメールアドレスとパスワードを用いた認証機能がデフォルトで用意されていません。今回はメールアドレスとパスワードでの簡易的な認証機能を作成する方法を紹介します。
注意
今回の方法で認証する場合、セッション管理はデータベースではなく JSON Web トークン(JWT)を使用して行われます。データベースでセッション管理を行いたい場合は、今回の方法は使えないのでご注意ください。
準備
Next.js アプリを作成
npx create-next-app password-auth-example
cd password-auth-example
必要なパッケージをインストール
npm i next-auth
[...nextauth].js ファイルを pages/api/auth に追加
mkdir pages/api/auth
touch "pages/api/auth/[...nextauth].js"
APIの設定
pages/api/auth/[...nextauth].js
import NextAuth from 'next-auth'
import Providers from 'next-auth/providers'
// credentials の情報から、ログイン可能か判定してユーザー情報を返す関数
const findUserByCredentials = credentials => {
// 今回は簡易的な例なのでメールアドレスとパスワードが一致する場合にユーザー情報を返却する。
// データベースでユーザーを管理している場合は、データベースからユーザーを取得して、パスワードハッシュを比較して判定するのがよいかと。
if (
credentials.email === process.env.USER_EMAIL &&
credentials.password === process.env.USER_PASSWORD
) {
// ログイン可ならユーザー情報を返却
return { id: 1, name: "Taro" }
} else {
// ログイン不可の場合は null を返却
return null
}
}
// NextAuth に渡すオプション
const options = {
// 認証プロバイダー
providers: [
Providers.Credentials({
// 表示名 ('Sign in with ...' に表示される)
name: "Email",
// credentials は、ログインページで適切なフォームを生成するために使用されます。
// 送信するフィールドを指定できます。(今回は メールアドレス と パスワード)
credentials: {
email: { label: "Email", type: "email", placeholder: "email@example.com" },
password: { label: "Password", type: "password" },
},
// 認証の関数
authorize: async credentials => {
const user = findUserByCredentials(credentials)
if (user) {
// 返されたオブジェクトはすべてJWTの`user`プロパティに保存される
return Promise.resolve(user)
} else {
// nullまたはfalseを返すと、認証を拒否する
return Promise.resolve(null)
// ErrorオブジェクトやリダイレクトURLを指定してコールバックをリジェクトすることもできます。
// return Promise.reject(new Error('error message')) // エラーページにリダイレクト
// return Promise.reject('/path/to/redirect') // URL にリダイレクト
}
},
}),
],
}
export default (req, res) => NextAuth(req, res, options)
ページの設定
pages/index.js
ログイン状態の場合は、「ユーザー名」と「Sign out ボタン」を表示し、
ログアウト状態の場合は、「Sign in ボタン」を表示します。
import { signIn, signOut, useSession } from 'next-auth/client'
export default function Home() {
const [ session, loading ] = useSession()
if (loading) {
return <div>Loading...</div>
}
return (
<div>
{session && (
<>
Signed in as {session.user.name} <br/>
<button onClick={signOut}>Sign out</button>
</>
)}
{!session && (
<>
Not signed in <br/>
<button onClick={signIn}>Sign in</button>
</>
)}
</div>
)
}
pages/_app.js
セッション状態をページ間で共有できるようにするために、NextAuth.js の Provider
を使用します。
import { Provider } from 'next-auth/client'
export default function MyApp({ Component, pageProps }) {
return (
<Provider session={pageProps.session}>
<Component {...pageProps} />
</Provider>
)
}
環境変数の設定
ローカル開発の場合、 .env.local ファイルにenv変数を追加します。
アプリのURLと、認証するユーザーのメールアドレスとパスワードを設定します。
NEXTAUTH_URL=http://localhost:3000
USER_EMAIL=email@example.com
USER_PASSWORD=password123
サイトを確認
npm run dev
を実行し、 localhost:3000 にアクセスするとWebサイトを確認できます。
ログインしていない状態なのがわかります。
Sign in ボタンを押すとログイン画面に遷移します。
環境変数に設定したメールアドレスとパスワードでログインするとホームに戻ります。
ログイン中なのでユーザー名が表示されます。
Sign out ボタンを押すとログアウトします。
以上です。NextAuth でメールアドレス/パスワードの簡易的な認証機能を追加することができました!
Discussion