Chrome拡張でSupabase × GitHub OAuthを実装するときのポイント

Chrome拡張でSupabase × GitHub OAuthを実装するときのポイント

今回は「Supabase + GitHub OAuth 認証を Chrome拡張でどう実装するか?」をテーマに、

実際にハマったポイントと、それをどう乗り越えたかをまとめます。


やりたかったこと

  • Chrome拡張内に GitHub ログインボタンを設置
  • Supabase の Auth 機能でログインセッション管理したい
  • GitHub の provider_token も取得して PRレビューに活かしたい
  • 出来るだけシンプル&セキュアな構成でやりたい

なぜ supabase.auth.signInWithOAuth() は使えないのか?

signInWithOAuth() は Web 向けに設計されており、内部で window.location によるリダイレクトが発生します。

でも Chrome拡張の popup や background では window.location の動作が制限されているため、使えません。

さらに chrome-extension:// のURLは OAuth における redirect_uri として使えないため、GitHub 側で弾かれてしまいます。

採用した構成(Implicit Flow パターン)

Chrome拡張で OAuth を行うためには、以下の流れを取りました:

  1. chrome.identity.launchWebAuthFlow() で Supabase の /auth/v1/authorize にアクセス
  2. Supabase が GitHub OAuth を開始
  3. 認証成功後、 Supabaseの /auth/v1/callback にリダイレクト
  4. Supabaseから拡張機能側 https://<extension-id>.chromiumapp.org/#access_token=... にリダイレクト
  5. そのURLを Chrome がキャッチし、トークンを取得
  6. supabase.auth.setSession() によりセッション確立

background.js で launchWebAuthFlow() を使う

launchWebAuthFlowを使うことで、拡張機能でも問題なくOAuthのプロセスを開始することができます。

const redirectUri = chrome.identity.getRedirectURL();

const authUrl = `https://<supabase-project>.supabase.co/auth/v1/authorize` +
  `?provider=github&redirect_to=${encodeURIComponent(redirectUri)}`;

chrome.identity.launchWebAuthFlow({ url: authUrl, interactive: true }, async (redirectUrl) => {
  const params = new URLSearchParams(new URL(redirectUrl).hash.slice(1));
  const access_token = params.get("access_token");
  const refresh_token = params.get("refresh_token");

  await supabase.auth.setSession({ access_token, refresh_token });
});

URL周りの設定

URL周りの設定を間違いやすいので注意です。

Supabaseのconfig.toml

[auth]
site_url = "https://<extension-id>.chromiumapp.org/"
additional_redirect_urls = [
  "https://<extension-id>.chromiumapp.org/"
]

Github 側の設定

GitHub OAuth App の Callback URL には以下を登録します。

https://<your-project>.supabase.co/auth/v1/callback

このURLは Supabase 側でGitHub OAuthの結果を受け取るための固定のコールバックです。

ハマったポイントとその回避法

この構成で特にハマったのは以下のような点です。

  • state の付与エラー:最初、/auth/v1/authorize のリクエストに state=xxx を自分で付けていたのですが、Supabase 側が内部で state を生成・検証しているため、自前の値と一致せずにエラー(invalid state)になっていました。解決策は、自分で state を付けず Supabase に任せることでした。
  • 拡張機能のURL設定ミス:Supabaseの site_url, additional_redirect_urlsで chrome-extension://<extension-id>/ のフォーマットにしていたところ、Authorization page could not be loaded というエラーが発生。https://<extension-id>.chromiumapp.org/ のフォーマットに変更して解決しました。

セキュリティ観点でどうか

今回の構成では、GitHub認証後のリダイレクトURLに #access_token=... が含まれるため、トークンがURLフラグメントに露出します。これはセキュリティ的に少し注意が必要です。

ただし、個人開発・社内利用・PoC用途であれば十分許容できる範囲だと考えています。

セッションが popup 側に伝わらない問題

background.js でログイン処理を行っても、popup 側では Supabase のセッションが認識されませんでした。これは拡張機能内でコンテキストが分かれているためで、解決策はトークンを chrome.storage.local に保存して、popup 側で読み出して setSession() し直すことでした。

以下のようにして chrome.storage.local に保存・復元することで、拡張の別コンテキスト(popupやcontent scriptなど)でもログイン状態を共有できます。

// 保存
chrome.storage.local.set({ access_token, refresh_token });

// 復元
chrome.storage.local.get(['access_token', 'refresh_token'], async (items) => {
  if (items.access_token) {
    await supabase.auth.setSession({
      access_token: items.access_token,
      refresh_token: items.refresh_token
    });
  }
});

おわりに

Supabase × GitHub OAuth × 拡張機能の組み合わせはまだ事例が少ないので、この記事が同じように詰まっている人の助けになれば嬉しいです 🙌

Anycloudではプロダクト開発の支援を行っています

プロダクト開発をお考えの方はぜひAnycloudにご相談ください。

まずは相談する

記事を書いた人

村井 謙太

代表取締役

村井 謙太

Twitter

東京大学在学中にプログラミング学習サービスのProgateを立ち上げ、CTOとしてプロダクト開発に従事。 Progate退任後に株式会社Anycloudを立ち上げ、現在は多数のクライアントの技術支援を行っている。