🌐

リバースプロキシ下で Next.js (v15) + Auth.js (v5) OAuth 認証を使う設定

2024/09/29に公開

はじめに

Next.js でWebアプリケーション開発をしています。
認証機能に Auth.js による Github/Twitter OAuth 認証を使用しています

デプロイ先としては、Next.js 開発元である Vercel とするのが最も簡単そうです......が、選択肢がそれしかないのは寂しいですから、レンタルサーバ中で Docker (Compose) を使用し、Nginxリバースプロキシ下(サブディレクトリ)で運用しています

サーバやドメイン(https://example.com)を一つしか持っていなくても、複数のNext.jsアプリケーション(next1, next2)を

  • https://example.com/next1
  • https://example.com/next2
    で待ち受けることが可能です

この条件で Next.js + Auth.js を動かす設定には一癖あり、随分時間が掛かりました。この記事では、Next.js (v15 App Router) + Auth.js (v5) をリバースプロキシ下(サブディレクトリ)で動かすため試行錯誤した結果をまとめます。

Nginx リバースプロキシ設定

https://example.com/girls-side-analysis へのアクセスを、Next.js アプリケーション(コンテナ名:girls-side-analysis-nextjs、ポート番号: 3000)に転送する設定です
https://github.com/Daiius/girls-side-analysis/blob/main/nginx.conf

proxy_pass設定について重要な選択肢があります。 上記の設定ファイルでは

  location /girls-side-analysis {
    proxy_pass http://girls-side-analysis-nextjs:3000; # 末尾の "/" なし
  }

としており、この設定では指定のサブディレクトリ名は転送時に保持されます

  • https://example.com/girls-side-analysishttp://girls-side-analysis-nextjs:3000/girls-side-analysis
  • https://example.com/girls-side-analysis/葉月珪http://girls-side-analysis-nextjs:3000/girls-side-analysis/葉月珪

結論から言うと、この設定の方が Next.js との相性が良いと考えます

もう一つの選択肢はこれです

  location /girls-side-analysis {
    proxy_pass http://girls-side-analysis-nextjs:3000/; # 末尾の "/" あり
  }

末尾の "/" を trailing slash と呼び、Trailing slash 有りだと指定のサブディレクトリ名が転送時に省かれます

  • https://example.com/girls-side-analysishttp://girls-side-analysis-nextjs:3000
  • https://example.com/girls-side-analysis/葉月珪http://girls-side-analysis-nextjs:3000/葉月珪

一般的にはこちらの構成が好まれる印象が有りますが、以下の理由から Next.js との相性が悪いです

Next.js の basePath 設定

上記の Nginx リバースプロキシ設定を行ったならば、 http://girls-side-analysis:3000/girls-side-analysis へのアクセス時に app/page.tsx を表示したいです
next.config.mjs ファイルで設定を行います
https://github.com/Daiius/girls-side-analysis/blob/main/next.config.mjs

これで Nginx + Next.js の設定が完了で、サブディレクトリ下で Next.js が動くようになります

Auth.js の設定

Auth.js は近年新しいバージョン v5 が出たためか、ドキュメントが整備されていません
先に必要/不要な設定を列挙しておくと、

  • 環境変数 NEXTAUTH_URL または AUTH_URL は指定しなくても大丈夫です
  • src/auth.ts で basePath を設定します、trustHost: true も設定します
  • src/middleware.tssrc/auth.ts の項目が反映された middleware を設定します
  • app/api/auth/[...nextauth]/route.ts に設定する認証用エントリポイントで、アクセスされたパスに basePath を付け足します
    (恐らく Auth.js の basePath 解析が一部不十分なのでは...?)
  • 必要ならば signIn, signOut 関数を呼ぶ際にリダイレクト先を指定します。もしくは src/auth.tspages 項目を設定します。
  • src/middleware.ts はキャッシュされる場合もあるかもしれないので、念のため開発環境をリロード(Next.js コンテナをリスタートし、再度 next dev)します

もしかしたら、アップデートによって上記の手順が一部不要になったり、実はもっと自然な設定方法がある...かもしれません
(その際には是非コメント等で教えて下さい)

src/auth.ts

こんな感じになります
https://github.com/Daiius/girls-side-analysis/blob/main/src/auth.ts

ポイントは以下になります

  • debug: true を指定するとその名の通りデバッグに有用なだけでなく、OAuth プロバイダからの様々な情報を受け取るために jwt 関数や session 関数をどう実装するべきかも判断しやすくなります(コンソールに情報が表示されます)
  • trustHost: true は docker (compose) 環境で用いるために必要です
  • basePath には Auth.js 用の認証用URLを指定します、/grils-side-analysis/api/auth を指定しています
  • callbacks: { async jwt(), async session() } には、OAuth プロバイダからの情報を JWT トークンに格納したり、JWT トークンから session を復元する方法を指定します
    OAuth Provider (Github, X(Twitter), Google) によって異なる処理が必要な場合が有ります

src/middleware.ts

どのページを middleware による認証の対象とするか選択します
https://github.com/Daiius/girls-side-analysis/blob/main/src/middleware.ts
今回は /profile ページで

  • 未認証の場合はサインイン用コンポーネント
  • 認証済みの場合はユーザ毎のコンテンツ+サインアウト用コンポーネント
    を切り替えて表示しますので、/profile ページのみが対象になっています。

`src/app/api/auth/[...nextauth]/route.ts

特に引っかかったポイントです、この辺に該当する Issue があります
https://github.com/nextauthjs/next-auth/issues/10928#issuecomment-2144241314
Auth.js の basePath 設定と、上記URLの解析([...nextauth] 部分のマッチング処理など)は現状噛み合っておらず、OAuth Provider 側でエラーが表示されたり、サインイン後に意図しないページにリダイレクトされたりします

対策として /api/auth/[...nextauth] へのアクセス時に、「アクセスされたのは /girls-side-analysis/api/auth/[...nextauth] ですよ」と嘘をつきます、こんな感じです
https://github.com/Daiius/girls-side-analysis/blob/main/src/app/api/auth/[...nextauth]/route.ts

signIn(), signOut() 関数のリダイレクト指定

src/auth.tspages オプションと重複するかもしれませんが、Auth.js の signIn(), signOut() 関数はオプション引数でリダイレクト先を指定できます

規定値は直前にいたページになるので、それでよければ指定の必要はありません

  signIn('twitter', { redirectTo: 'https://example.com/girls-side-analysis/profile' });
  signOut({ redirectTo: 'https://example.com/girls-side-analysis/profile' });

docker-compose.yml

この様な docker-compose ファイルで開発環境を起動しています。
https://github.com/Daiius/girls-side-analysis/blob/main/docker-compose.yml

さいごに

Vercel ではサブドメインを用いて複数の Next.js アプリケーションを管理しますから、わざわざ上記の構成で動かすもの好きはいない......のかもしれません
何かお役に立てば幸いです!

Discussion