リバースプロキシ下で Next.js (v15) + Auth.js (v5) OAuth 認証を使う設定
はじめに
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)に転送する設定です
proxy_pass
設定について重要な選択肢があります。 上記の設定ファイルでは
location /girls-side-analysis {
proxy_pass http://girls-side-analysis-nextjs:3000; # 末尾の "/" なし
}
としており、この設定では指定のサブディレクトリ名は転送時に保持されます
-
https://example.com/girls-side-analysis
→http://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-analysis
→http://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
ファイルで設定を行います
これで Nginx + Next.js の設定が完了で、サブディレクトリ下で Next.js が動くようになります
Auth.js の設定
Auth.js は近年新しいバージョン v5 が出たためか、ドキュメントが整備されていません
先に必要/不要な設定を列挙しておくと、
- 環境変数
NEXTAUTH_URL
またはAUTH_URL
は指定しなくても大丈夫です -
src/auth.ts
で basePath を設定します、trustHost: true
も設定します -
src/middleware.ts
でsrc/auth.ts
の項目が反映された middleware を設定します -
app/api/auth/[...nextauth]/route.ts
に設定する認証用エントリポイントで、アクセスされたパスに basePath を付け足します
(恐らく Auth.js の basePath 解析が一部不十分なのでは...?) - 必要ならば
signIn
,signOut
関数を呼ぶ際にリダイレクト先を指定します。もしくはsrc/auth.ts
のpages
項目を設定します。 -
src/middleware.ts
はキャッシュされる場合もあるかもしれないので、念のため開発環境をリロード(Next.js コンテナをリスタートし、再度next dev
)します
もしかしたら、アップデートによって上記の手順が一部不要になったり、実はもっと自然な設定方法がある...かもしれません
(その際には是非コメント等で教えて下さい)
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 による認証の対象とするか選択します/profile
ページで
- 未認証の場合はサインイン用コンポーネント
- 認証済みの場合はユーザ毎のコンテンツ+サインアウト用コンポーネント
を切り替えて表示しますので、/profile
ページのみが対象になっています。
`src/app/api/auth/[...nextauth]/route.ts
特に引っかかったポイントです、この辺に該当する Issue があります
Auth.js の basePath 設定と、上記URLの解析([...nextauth] 部分のマッチング処理など)は現状噛み合っておらず、OAuth Provider 側でエラーが表示されたり、サインイン後に意図しないページにリダイレクトされたりします対策として /api/auth/[...nextauth]
へのアクセス時に、「アクセスされたのは /girls-side-analysis/api/auth/[...nextauth]
ですよ」と嘘をつきます、こんな感じです
signIn()
, signOut()
関数のリダイレクト指定
src/auth.ts
の pages
オプションと重複するかもしれませんが、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 ファイルで開発環境を起動しています。
さいごに
Vercel ではサブドメインを用いて複数の Next.js アプリケーションを管理しますから、わざわざ上記の構成で動かすもの好きはいない......のかもしれません
何かお役に立てば幸いです!
Discussion