📌

NextAuthのmiddlewareでページごとの認証チェックを実装する

2022/12/13に公開

PitPaでエンジニアをしています、hideです。
現在T3 Stackでプロダクト開発を行っています。

T3 Stackでは認証ライブラリとしてNextAuth.jsが使われており、今回NextAuth.jsのmiddlewareを使ってページごと認証チェックをする方法について調べたので記しておきます。

使用したバージョン

  • next: 13.0.2
  • next-auth: 4.17.0

middlewareでの設定

(Nexts.jsにおける)middlewareとは、pageへのリクエストを受け取った時にコードを実行できる機能です。
https://nextjs.org/docs/advanced-features/middleware
src/直下にmiddleware.ts(js)を作成することで使うことができます。

認証チェックを行うにはmiddleware.tsnext-authが用意しているmiddlewareをexportするようにします。
https://nextjs.org/docs/advanced-features/middleware#matcher

src/middleware.ts
export { default } from "next-auth/middleware";

基本的な使い方としては上記設定だけでページへのリクエスト時に認証チェックを行い、認証に失敗すればサインイン画面にリダイレクトされます。

これだと全てのページに対して認証チェックが走ってしまいますが、さらにconfigオブジェクトをexportすることで適用するページを設定することができます。
こちらはnextの機能で、middleware.tsで設定した処理を特定のパスで実行できるようになります。
https://nextjs.org/docs/advanced-features/middleware#matcher

src/middleware.ts
export { default } from "next-auth/middleware";

export const config = {
  matcher: [
    "/",
    "/((?!non-protected).*)"
  ],
};

上記の設定で、トップページ/へのリクエスト時に認証チェックを行うのと、
正規表現も使えるため、/non-protected以外の/配下の全ページに対して認証チェックを行うことができるようになりました。

next-authのコードを追ってみる

認証失敗時のリダイレクト先は?

https://github.com/nextauthjs/next-auth/blob/next-auth%40v4.17.0/packages/next-auth/src/next/middleware.ts#L106
https://github.com/nextauthjs/next-auth/blob/next-auth%40v4.17.0/packages/next-auth/src/next/middleware.ts#L147-L150
オプションでsigninページが設定されていればそこに、デフォルトでは/api/auth/signinにリダイレクトされます。
(/api/auth/配下はnext-authがデフォルトで用意してくれている画面・apiです)
オプションは以下のように、middlewareをラップする書き方で実装した場合に設定することができます。
https://next-auth.js.org/configuration/nextjs#wrap-middleware

middlewareのconfigで/api/auth/signinを除外してないのにアクセスできるのはなぜ?

上記でリダイレクト先のデフォルトは/api/auth/signinと書きましたが、
middleware.tsのconfigで除外の設定をしていないはずなのに/api/auth/signinにはsigninしていなくてもアクセスできます。
それは、
https://github.com/nextauthjs/next-auth/blob/next-auth%40v4.17.0/packages/next-auth/src/next/middleware.ts#L106-L119
authPathが、認証チェックをせずにreturnするパス、の対象となっているためです。
/_next, /_favicon.icoも認証チェックの対象から外れています。

おわり

認証が必要なページを明示的に書いていくと、新たなページを作る際に対応が漏れてしまい、見せてはいけないページが見えてしまう可能性があります。
middlewareを使うことによって、デフォルトですべてのpageを認証チェックでき、正規表現によって不要なページだけを明示的に書けるので、見せてはいけないページが見えてしまう事が発生しないのでいいなと思いました。

PitPa Tech Blog

Discussion