SvelteKit + Azure Static Web Apps で認証を実現する

# はじめに

以下の投稿で、[SvelteKit] で作成した Web アプリを Azure Static Web Apps にデプロイできました。

https://qiita.com/fsd-tetsu/items/151a5bc49c8b8acefb04

今回はこのアプリに認証機能を付けてみます。

# 仕様

とりあえず、全てのパスへのアクセスに対して必ず認証が必要、という仕様にします。

# 実現方法

以下にカスタマイズ方法が記載されていました。

https://github.com/geoffrich/svelte-adapter-azure-swa/#customstaticwebappconfig

```js:svelte.config.js
import azure from 'svelte-adapter-azure-swa';
import { vitePreprocess } from '@sveltejs/kit/vite';

/** @type {import('@sveltejs/kit').Config} */
const config = {
	// Consult https://kit.svelte.dev/docs/integrations#preprocessors
	// for more information about preprocessors
	preprocess: vitePreprocess(),

	kit: {
		adapter: azure({
			customStaticWebAppConfig: {
				routes: [
					{
						route: '*',
						allowedRoles: ['admin']
					}
				],
				responseOverrides: {
					"401": {
						"redirect": "/.auth/login/github?post_login_redirect_uri=.referrer",
						"statusCode": 302
					}
				}
			}
		})
	}
};
export default config;
```

# ビルドしてみる

ビルドしてみます。

```:ターミナル
npm run build
...
> Using adapter-azure-swa
error during build:
Error: customStaticWebAppConfig cannot override '*' route.
    at validateCustomConfig (file:///workspace/node_modules/svelte-adapter-azure-swa/index.js:41:10)
    at generateConfig (file:///workspace/node_modules/svelte-adapter-azure-swa/index.js:166:2)
    at adapt (file:///workspace/node_modules/svelte-adapter-azure-swa/index.js:64:22)
    at adapt (file:///workspace/node_modules/@sveltejs/kit/src/core/adapt/index.js:26:8)
    at finalise (file:///workspace/node_modules/@sveltejs/kit/src/exports/vite/index.js:805:13)
    at async Object.handler (file:///workspace/node_modules/@sveltejs/kit/src/exports/vite/index.js:827:5)
    at async PluginDriver.hookParallel (file:///workspace/node_modules/rollup/dist/es/shared/node-entry.js:24317:17)
    at async Object.close (file:///workspace/node_modules/rollup/dist/es/shared/node-entry.js:25625:13)
    at async build (file:///workspace/node_modules/vite/dist/node/chunks/dep-79892de8.js:46256:13)
    at async CAC.<anonymous> (file:///workspace/node_modules/vite/dist/node/cli.js:813:9)
```
エラーが発生しました。
`*` という `route` は定義済みだから上書きできない、って言われちゃいました。

# 問題点の確認

デフォルトで生成される `build/staticwebapp.config.json` はこんな感じです。
```json:build/staticwebapp.config.json
{
  "routes": [
    {
      "route": "*",
      "methods": [
        "POST",
        "PUT",
        "DELETE"
      ],
      "rewrite": "/api/__render"
    },
    {
      "route": "/_app/immutable/*",
      "headers": {
        "cache-control": "public, immutable, max-age=31536000"
      }
    },
    {
      "route": "/index.html",
      "rewrite": "/api/__render"
    },
    {
      "route": "/",
      "rewrite": "/api/__render"
    }
  ],
  "navigationFallback": {
    "rewrite": "/api/__render"
  },
  "platform": {
    "apiRuntime": "node:16"
  }
}
```
確かに `"route": "*"` が既に存在しますね。
以下の issue で言及されているとおり、どうやら [adapter-azure-swa] ではこの問題に対象できないっぽいです。

- [issues/102](https://github.com/geoffrich/svelte-adapter-azure-swa/issues/102)
- [issues/134](https://github.com/geoffrich/svelte-adapter-azure-swa/issues/134)

さて、どうしましょう...

# 解決策

自前の `staticwebapp.config.json` を用意しておいて、ビルド後に `build/staticwebapp.config.json` を上書きすることで対処できました。

まずは、自前の `staticwebapp.config.json` を作成。
```diff_jsonnet:confg/staticwebapp.config.json
{
  "routes": [
    {
      "route": "*",
      "methods": [
        "POST",
        "PUT",
        "DELETE"
      ],
      "rewrite": "/api/__render",
+      "allowedRoles": ["authenticated"]
    },
    {
      "route": "/_app/immutable/*",
      "headers": {
        "cache-control": "public, immutable, max-age=31536000"
      }
    },
    {
      "route": "/index.html",
      "rewrite": "/api/__render",
+      "allowedRoles": ["authenticated"]
    },
    {
      "route": "/",
      "rewrite": "/api/__render",
+      "allowedRoles": ["authenticated"]
    },
+    {
+      "route": "*",
+      "methods": ["GET"],
+      "allowedRoles": ["authenticated"]
+    }
  ],
  "responseOverrides": {
    "401": {
      "redirect": "/.auth/login/github?post_login_redirect_uri=.referrer",
      "statusCode": 302
    }
  },
  "navigationFallback": {
    "rewrite": "/api/__render"
  },
  "platform": {
    "apiRuntime": "node:16"
  }
}
```

ビルド後に上書きするように修正。
```diff_jsonnet:package.json
{
    ...
	"scripts": {
		"dev": "vite dev",
-		"build": "vite build",
+		"build": "vite build && cp config/staticwebapp.config.json build",
		"preview": "vite preview",
        ...
	},
    ...
}
```

もちろん、`svelte.config.js` は元に戻す。
```diff_javascript:svelte.config.js
import azure from 'svelte-adapter-azure-swa';
import { vitePreprocess } from '@sveltejs/kit/vite';

/** @type {import('@sveltejs/kit').Config} */
const config = {
	// Consult https://kit.svelte.dev/docs/integrations#preprocessors
	// for more information about preprocessors
	preprocess: vitePreprocess(),

	kit: {
-		adapter: azure({
-			customStaticWebAppConfig: {
-				routes: [
-					{
-						route: '*',
-						allowedRoles: ['admin']
-					}
-				],
-				responseOverrides: {
-					"401": {
-						"redirect": "/.auth/login/github?post_login_redirect_uri=.referrer",
-						"statusCode": 302
-					}
-				}
-			}
-		})
+		adapter: azure()
	}
};

export default config;
```

# 結果

Static Web Apps にデプロイしてアクセスしてみたところ、ちゃんと GitHub のログイン画面が表示されました。

# まとめ

一番簡単な認証の仕組みを導入したかったのですが、思わぬ問題に遭遇しました。ただ、[adapter-azure-swa] の仕組みが分かり易かったため、シンプルに対処できました。

この辺は需要が多そうなので [issues/134](https://github.com/geoffrich/svelte-adapter-azure-swa/issues/134) の動向を注視していきたいと思います。:smiley:

[SvelteKit]:https://kit.svelte.dev/
[adapter-azure-swa]:https://github.com/geoffrich/svelte-adapter-azure-swa/