SvelteKit + GitHub OAuthをCloudflare Workersにデプロイした話(躓きポイントまとめ)

ローカルで動作確認済みのGitHub OAuth認証をCloudflare Workersにデプロイする際、環境変数まわりで複数の躓きポイントがありました。 同じ構成(SvelteKit + adapter-cloudflare + wrangler deploy)を使う場合の参考になるようにまとめます。

構成

  • SvelteKit + @sveltejs/adapter-cloudflare
  • Cloudflare Pages(GitHub連携)経由で npx wrangler deploy でデプロイ
  • 環境変数:GITHUB_CLIENT_IDGITHUB_CLIENT_SECRET

躓き① $env/static/private はビルド時にしか読めない

症状

[MISSING_EXPORT] Error: "GITHUB_CLIENT_ID" is not exported by "\0virtual:env/static/private".

原因

SvelteKitの $env/static/private はビルド時に値を読み込みます。Cloudflare Pagesのビルド環境では、ダッシュボードの「変数とシークレット」はランタイム(Worker実行時)にしか使えないため、ビルド時には見つからずエラーになります。

// ❌ ビルド時に値が必要なためCloudflareのランタイム変数では使えない
import { GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET } from '$env/static/private';

解決策

platform.env を使ってランタイムに値を読み込みます。

// ✅ ランタイムにCloudflare WorkerのenvからアクセスするためOK
export const GET: RequestHandler = async ({ platform }) => {
  const clientId = platform!.env.GITHUB_CLIENT_ID;
  const clientSecret = platform!.env.GITHUB_CLIENT_SECRET;
};

app.d.tsPlatform インターフェースに型定義を追加します。

// src/app.d.ts
interface Platform {
  env: {
    DB: D1Database;
    GITHUB_CLIENT_ID: string;
    GITHUB_CLIENT_SECRET: string;
  };
}

躓き② コールバックURLをハードコードしていた

症状

src/lib/auth.ts にローカル用のURLがハードコードされていた。

// ❌ 本番では異なるURLになるためハードコードはNG
export const github = new GitHub(
  GITHUB_CLIENT_ID,
  GITHUB_CLIENT_SECRET,
  'http://localhost:8787/login/github/callback'
);

解決策

url.origin からコールバックURLを動的に生成します。ローカルでは http://localhost:8787、本番では https://本番ドメイン に自動的になります。

// src/lib/auth.ts
export function createGitHubClient(clientId: string, clientSecret: string, callbackUrl: string) {
  return new GitHub(clientId, clientSecret, callbackUrl);
}
// src/routes/login/github/+server.ts
export const GET: RequestHandler = async ({ url, cookies, platform }) => {
  const callbackUrl = `${url.origin}/login/github/callback`;
  const github = createGitHubClient(
    platform!.env.GITHUB_CLIENT_ID,
    platform!.env.GITHUB_CLIENT_SECRET,
    callbackUrl
  );
  // ...
};

躓き③ Cloudflareダッシュボードの変数が wrangler deploy に反映されない

症状

Cloudflareダッシュボードの「変数とシークレット」に GITHUB_CLIENT_ID を登録したのに、platform.env.GITHUB_CLIENT_IDundefined になる。

GitHubの認証URLを見ると client_id=undefined になっていた。

https://github.com/login/oauth/authorize?client_id=undefined&...

原因

Cloudflareダッシュボードの「変数とシークレット」は、npx wrangler deploy で作成されたWorkerには自動では反映されません。

デプロイ時のバインディング一覧にも GITHUB_CLIENT_ID が含まれていませんでした。

Your Worker has access to the following bindings:
env.DB (sveltekit-blog-db)   D1 Database   ← D1は反映される
env.ASSETS                   Assets
# GITHUB_CLIENT_ID は含まれていない

解決策

wrangler secret put コマンドで直接Workerにシークレットを登録します。

npx wrangler secret put GITHUB_CLIENT_ID
npx wrangler secret put GITHUB_CLIENT_SECRET

実行するとそれぞれ値の入力を求められます。再デプロイ不要で即座にWorkerから参照できるようになります。

登録後はダッシュボードにも反映されて表示されます。ダッシュボード上の表示と wrangler secret put で登録した値は同じものです。ダッシュボードから削除すると参照できなくなるので削除しないでください。


ローカル開発での注意点

platform.env を使うようにした場合、ローカル開発では .env ではなく .dev.vars ファイルにシークレットを書きます。wranglerがこのファイルを読み込んで platform.env に渡します。

# .dev.vars(gitignoreに追加すること)
GITHUB_CLIENT_ID=ローカル用OAuthアプリのClient ID
GITHUB_CLIENT_SECRET=ローカル用OAuthアプリのClient Secret

ローカル用と本番用でOAuthアプリを分けることで、GitHubのOAuth Appsの設定を切り替えなくても両環境でそれぞれ動きます。


まとめ

躓きポイント 原因 解決策
$env/static/private でビルドエラー ビルド時に変数が必要だがCloudflareはランタイムのみ platform.env を使う
コールバックURLのハードコード 環境ごとにURLが変わる url.origin から動的生成
ダッシュボード変数が反映されない wrangler deploy Workerにはダッシュボード変数が反映されない wrangler secret put を使う

Cloudflare WorkersとSvelteKitの組み合わせでは、環境変数を platform.env 経由で読む設計にして、シークレットは wrangler secret put で管理するのが正解です。

← トップページに戻る