はじめに
こんにちは。ニフティ株式会社に入社して新卒四年目の佐々木です。
今回は、業務で触れる機会のあった「NextAuth.js」について紹介したいと思います。
この記事の内容
- NextAuth.jsの特徴
- NextAuth.jsの実装方法
NextAuth.jsとは
NextAuth.jsとは、Next.jsで認証機能を実装するためのライブラリです。
特徴
NextAuth.jsの特徴としては以下になります。
- セッションデータの保存をデータベースなしでも使用できる
- サーバーレス環境向けに設計されている(それ以外の環境でも利用はできる)
- デフォルトの設定でセキュアになるように設計されている
ログインのセッションについては、データベースを使用せずにJWTで管理することができます。
例えばユーザー情報をアプリケーション側に保持しなくても良い場合は、「ログイン機能のためにデータベースを用意する」といった手間も省くことが可能です。
認証を行うコンポーネントを自前で実装する方法もありますが、NextAuth.jsといったライブラリを利用した方が、自前で実装したときと比較してアプリケーション以外にかけるコスト(運用やセキュリティ面のリスク)を下げることができると思います。
実装してみる
次に、NextAuth.jsを利用した際の実装例について紹介したいと思います。
NextAuth.jsでの認証の実装で作成するファイルは以下になります。
- pages/api/auth/[…nextauth].js:認証プロバイダーやセッション保存方法を指定するために必要
- pages/_app.js:Sessionオブジェクトを取得できるようにするために必要
- pages/index.js: ログイン処理の実装を埋め込むために必要
- next.config.js: 本番環境で外部の環境変数を参照するために必要
前提条件
- 技術:NextAuth.js(v4) + Next.js + React
- セッション格納方法:JWT
- Next.jsのアプリケーションは作成済み
(NextAuth.jsはv3系からv4系へのアップデートで大きな変更が入ったため、今回は最新版であるv4系での紹介となります。詳細はこちらをご参照ください。)
インストール
まずは必要なパッケージのインストールを行います。
1 |
yarn add next-auth |
pages/api/auth/[…nextauth].js
NextAuth.jsを組み込むには、pages/api/auth配下に[…nextauth].jsというファイルを用意する必要があります。
認証プロバイダー
認証プロバイダーを指定するため、providerオプションを追加します。認証プロバイダーに関しては、clientId、clientSecretなどの指定を行います。
認証プロバイダーには組み込みのプロバイダーも用意されており、Google、Twitter、Githubといった有名なプロバイダーであればこちらから利用が可能です。
例として、Googleをプロバイダーとして指定する場合は以下のようになります。
1 2 3 4 5 6 7 8 9 10 |
import NextAuth from "next-auth" import GoogleProvider from 'next-auth/providers/google'; export default NextAuth({ providers: [ GoogleProvider({ clientId: process.env.GOOGLE_CLIENT_ID, clientSecret: process.env.GOOGLE_CLIENT_SECRET, }), ], }) |
ちなみに、指定するプロバイダーについては、自前で用意した任意のカスタムプロバイダーを指定することもできます。詳細はNextAuth.jsの公式ドキュメントをご参照ください。
セッション
次に、セッションの保存方法を指定するため、sessionオプションを追加します。
NextAuth.jsは、デフォルトでDBを使用せずJWTのみでセッション管理とユーザ情報の管理を行います。しかし、公式のFAQ( https://next-auth.js.org/faq#databases )の例にあるようなDBへのユーザ情報の保存が必要なケースでは、strategyをdatabaseに指定しDBに接続するためのadapterを別途用意します。
今回はJWTでセッション管理を行うため、strategyをjwtに指定します。
1 2 3 4 5 6 7 |
providers: { ... }, session: { strategy: "jwt", maxAge: 30 * 24 * 60 * 60, }, |
pages/_app.js
SessionProviderの設定
後ほど設定するuseUsession()でSessionオブジェクトを取得できるようにするために、<SessionProvider>を設定する必要があります。取得したセッションは同じアプリケーションが動くすべてのブラウザタブ/ウインドウで同期されるようになります。
pages/_app.jsに以下を追加します。
1 2 3 4 5 6 7 8 9 10 11 12 |
import { SessionProvider } from "next-auth/react" export default function App({ Component, pageProps: { session, ...pageProps }, }) { return ( <SessionProvider session={session}> <Component {...pageProps} /> </SessionProvider> ) } |
pages/index.js
NextAuth.jsにはClient APIといったものが用意されており、これらのフック関数を使用することでログイン処理や、セッション情報の判定といった操作を簡単に行うことができます。
ログイン・ログアウト
pages/index.js内でログインボタンを設置し、クリックした際に サインイン処理 が実行されるようにします。
signiIn()関数を使用すると、NextAuth.jsのサインインの中間ページにリダイレクトされます。
1 2 3 |
import { signIn } from "next-auth/react" export default () => <button onClick={() => signIn()}>Sign in</button> |
signIn()関数の第1引数にGoogleなどのプロバイダー名を指定することで、NextAuth.jsの中間ページをスキップして直接ログインさせることもできます。
また、第2引数にcallbackUrlを指定すると、ユーザーがサインイン後にリダイレクトで戻ってくるページを任意のURLに変更もできます。ログイン後に別ページにリダイレクトさせたい場合には使えそうですね。
1 2 3 |
import { signIn } from "next-auth/react" export default () => <button onClick={() => signIn('google', { callbackUrl: 'http://localhost:3000/bar' })}>Sign in</button> |
ログアウトさせたい場合は signout()関数を使用します。
1 2 3 |
import { signOut } from "next-auth/react" export default () => <button onClick={() => signOut()}>Sign out</button> |
セッション情報の利用
NextAuth.jsでログインすると、sessionにユーザー情報が格納されます。
それらを利用して、ログイン後に別のコンポーネントを表示させたり、ユーザーごとにクライアント側の処理を変更させる、というように簡単にクライアント側のみで動作のカスタマイズが可能です。
クライアント側からsession情報にアクセスするにはuseSession()を利用します。useSession()はクライアントアプリケーションのどの階層からでも呼び出すことができます。
以下がその利用例です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
import { useSession, signIn, signOut } from "next-auth/react" export default function Component() { const { data: session } = useSession() if (session) { return ( <> Signed in as {session.user.email} <br /> <button onClick={() => signOut()}>Sign out</button> </> ) } return ( <> Not signed in <br /> <button onClick={() => signIn()}>Sign in</button> </> ) } |
環境変数の設定
ローカル環境で試す場合
先程[…nextauth].jsに記述した、clientId や callbackUrl などの値を env.local に環境変数として設定します。
1 2 |
GOOGLE_CLIENT_ID=xxx GOOGLE_CLIENT_SECRET=xxx |
本番環境にデプロイする場合
本番環境にデプロイする場合は、ローカル環境で設定した値に加えて以下の環境変数を追加します。
- NEXTAUTH_URL
- NEXTAUTH_SECRET
NEXTAUTH_URL
NEXTAUTH_URLにはサイトの正規URLを指定します。
NEXTAUTH_SECRET
NEXTAUTH_SECRETにはデフォルトのシークレットの値を指定します。この値はJWTを暗号化しトークンをハッシュするために使用します。
(本番環境ではNEXTAUTH_SECRETの値が定義されていないとエラーが発生するため)
また、シークレットにはopensslコマンドでランダムな文字列を生成すると便利です。
1 |
openssl rand -base64 32 |
環境変数の追加方法
本番環境などにデプロイする際には env.local だと環境変数として利用できないので、外部から値を参照できるようにする必要があります。
next.config.js というファイルを作成し、外部の環境変数を参照できるようにします。
1 2 3 4 5 6 7 8 9 |
require("dotenv").config(); module.exports = { env: { GOOGLE_CLIENT_ID: process.env.GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET: process.env.GOOGLE_CLIENT_SECRET, NEXTAUTH_URL: process.env.NEXTAUTH_URL, NEXTAUTH_SECRET: process.env.NEXTAUTH_NEXTAUTH_SECRET, }, }; |
さいごに
導入としては簡単になりますが、今回はNextAuth.jsのライブラリについて紹介しました。
NextAuth.jsには他にもオプションや機能などが充実しているので、もし興味があるという方は使ってみてください!