React(Next.js)のStatic Exports設定で認証ロジックを実装する②

[株式会社 ONE WEDGE](https://onewedge.co.jp/)の[@Shankou](https://qiita.com/Shankou)です。
前回から引き続き、認証ロジックを実装していきたいと思います。

## ライブラリのインストール
まずは、いくつかライブラリをインストールしていきたいと思います。

### env-cmd
Next.jsにはデフォルトで環境設定ファイルを使い分けられる機能が備わっています。
[Default Environment Variables](https://nextjs.org/docs/pages/building-your-application/configuring/environment-variables#default-environment-variables)

しかしながら、もっと柔軟に環境変数ファイルを切り分けたいという場合もあるかと思います。
そんなときに便利なのが`env-cmd`です。

https://www.npmjs.com/package/env-cmd

```
> npm i env-cmd
```

このライブラリをインストールすると、以下の様にenvファイルを指定してビルドを行うことができます。
Next.jsで決められた環境名以外の名前をつけることが可能です。

```
env-cmd -f .env.hoge next build
```

一部抜粋した形で記載しますが、`package.json`に以下のようにスクリプトを登録しておくと楽ができます。

```package.json
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "build:hoge": "env-cmd -f .env.hoge next build",
    "build:fuga": "env-cmd -f .env.fuga next build",
```

```
> npm run build:hoge
```

### Axios
個人的に使い慣れているからという理由で`Axios`を使っていますが、`Fetch API`でもいいと思います。

https://www.npmjs.com/package/axios

```
> npm i axios
```

### Zod
`Zod`はTypeScript向けのスキーマ宣言とデータ検証のためのライブラリです。
APIのレスポンスデータを`parse`関数で型情報付きのオブジェクトへいっぱつで変換してくれます。
(スキーマ情報は自分で設定する必要はありますが)

https://www.npmjs.com/package/zod

```
> npm i zod
```

## サーバーレスにおける認証について
認証ロジックを実装する！と言っておいてなんですが、サーバーレス開発には認証トークンの管理をどうするかという問題があります。
JavascriptではXSSを筆頭に「任意のJavascriptコードが実行されてしまう」というリスクを常に考える必要があります。サーバーコードがあれば`サーバーサイドセッション`で管理することで、XSSに対しては安全性が担保されます。ですが、サーバーレスではそうは行きません。Javascriptで保持・管理する都合上、常にリスクが存在するのです。

じゃあ、どうするか！

これが一筋縄ではいかないのです。
外部の認証サービスを使えるのであれば`Auth0`等を利用するのがいいかと思います。ただし、こちらはコストがかかりますね。
完全に自前で実装する場合、インメモリ(変数)で保持して外部から参照できない領域で管理するというのが一番セキュアにはなりますが、リロードをするとログインをやり直す必要が出てきます。ユーザビリティ的に残念。
永続化にはどうしてもローカルストレージが必要となるわけですが、ローカルストレージはXSSに激弱です。
そのため、暗号化等で攻撃難易度を上げるという対処療法を取る必要がありますが、難易度を上げているだけなので安心安全というわけではありません。
こういったリスクを把握した上でサーバーレス開発を行う必要があるという点に注意してください。

ちなみに、Auth0ではWebWorkerでアクセストークンを管理し、サーバーサイドセッションでリフレッシュトークンを管理するという方式をとっているっぽいです？多分。

今回はSampleということでセキュリティ対策は皆無！
全裸でローカルストレージにインします！


## ルーティング定義
Next.jsではルーティングをディレクトリ構造で表現することができるのですが、いくつかの特殊記法が存在します。
その一つがディレクトリ名を`()`で囲うことによりルーティングに影響を与えずにグループ化するというものです。
この機能を使って認証が必要なページとそれ以外とを分けていきます。
ディレクトリ構成は以下の通りです。

```
src
　　┗　app
  　　　　┣　()　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　# 認証なしルーティンググループ
    ┃ 　┝　layout.tsx
    ┃　　　┝　page.tsx
    ┃　　　└　login
    ┃　　　　　　　　└　page.tsx
    ┃
    ┗　(authenticated)　　　　　# 認証ありルーティンググループ
　　　　　　　　　　　　　　┝　layout.tsx
　　　　　　　　　　　　　　└　mypage
　　　　　　　　　　　　　　　　　　　└　page.tsx
```

この構成により、以下のルートが定義でき、認証の有無をグループ化して切り分けることができました。
- 認証なし
  - /
  - /login
- 認証あり
  - /mypage

ちなみに、他の特殊記法としてディレクトリ名を`[]`で囲むことにより、ダイナミックルーティングが可能です。
ダイナミックルーティングというのは、例えば`/users/[userId]/page.tsx`というように構成すると、`[userId]`は可変でユーザIDが入るようなルーティングを定義することができます。更に`page.tsx`では、その値を容易に参照し利用することができるのです。

本来であれば…

悲しいことに、Static Exportsではこの機能が動作しません。

https://github.com/vercel/next.js/discussions/55393

[最新のコメント(2024/08/07)](https://github.com/vercel/next.js/discussions/55393#discussioncomment-10262206)では、

> 社内でこの機能をサポートするための提案書を作成しました。今後数か月以内にさらに更新情報をお伝えできればと思います 🙏。

とのことですので、将来的には対応されるようですが、今現在・今後数ヶ月はこの機能を使うことができないので注意が必要です。

##
あれもこれもと思っていたら、まだまだ長くなりそうなので、一旦ここまで。
次回こそ認証ロジックの実装に入ります！

next > [③](https://qiita.com/Shankou/items/76d2a244c150bf367a2a)