Slide 1

Slide 1 text

© 2025 Wantedly, Inc. Wantedly Tech Night Apollo Sandbox における 認証トークンの自動適用 Mar. 19 2025 - Toranosuke Ujike

Slide 2

Slide 2 text

© 2025 Wantedly, Inc. 氏家 虎之介 Toranosuke Ujike Quality Control Squad, Wantedly, Inc. 2023 New Grads @tora_tora_bit @torabit

Slide 3

Slide 3 text

© 2025 Wantedly, Inc. Apollo Sandbox で 認証が必要な API を楽に叩きたい どんな発表?

Slide 4

Slide 4 text

© 2025 Wantedly, Inc. 同じ課題に直面している開発者の参考になると嬉しい どんな発表? 拡張機能や API の活用方法についての知見共有 開発プロセスの工夫や試行錯誤を知ってもらう 目的は?

Slide 5

Slide 5 text

© 2025 Wantedly, Inc. 開発環境の改善 どんな内容? 試行錯誤とその結果 なにをしたの? Apollo Sandbox × Access token の問題 制約を踏まえた上での設計

Slide 6

Slide 6 text

© 2025 Wantedly, Inc. 話すこと 背景 課題 解決策 Wantedly Hire アプリケーションについて Access token 管理と期限について Apollo Sandbox ストレスの原因 解決策とその評価 失敗した作戦一覧 最終解決策 demo を交えて紹介

Slide 7

Slide 7 text

© 2025 Wantedly, Inc. Wantedly Hire アプリケーションについて 7 7 次世代型 採用管理システム 採用プロセスの悩みを解決 途中辞退を防ぐための業務を効率化 ● 繰り返しフローで候補者管理を自動化 ● 複数名の自動日程調整で 80%時間を削減 多様化する採用プロセスに対応 ● 最適な選考プロセスを自由自在に構築 ● 多様なメンバーに適した権限 構造化面接で高精度の見極め可能 ● 採用基準の標準化・カスタマイズ ● 各項目の評価を定量化

Slide 8

Slide 8 text

© 2025 Wantedly, Inc. Wantedly Hire 技術スタック FRONTEND API GATEWAY BACKEND

Slide 9

Slide 9 text

© 2025 Wantedly, Inc. Wantedly Hire 技術スタック FRONTEND API GATEWAY BACKEND

Slide 10

Slide 10 text

© 2025 Wantedly, Inc. 話すこと 背景 課題 解決策 Wantedly Hire アプリケーションについて Access token 管理と期限について Apollo Sandbox ストレスの原因 解決策とその評価 失敗した作戦一覧 最終解決策 demo を交えて紹介

Slide 11

Slide 11 text

© 2025 Wantedly, Inc. Access token 期限について Wantedly Hire は採用周りの機密情報を取り扱っている そのためアクセストークンの有効期限は数時間

Slide 12

Slide 12 text

© 2025 Wantedly, Inc. Access token 管理について Q. アクセストークンの有効期限が切れた場合は? A. リフレッシュトークンを使って再発行を行う Q. どこに保管しているの? A. HTTP Cookie に保管している

Slide 13

Slide 13 text

© 2025 Wantedly, Inc. 話すこと 背景 課題 解決策 Wantedly Hire アプリケーションについて Access token 管理と期限について Apollo Sandbox ストレスの原因 解決策とその評価 失敗した作戦一覧 最終解決策 demo を交えて紹介

Slide 14

Slide 14 text

© 2025 Wantedly, Inc. Apollo Sandbox 前提 Wantedly Hire の API のほとんどは認証が必要 HTTP Header に Authorization を含める必要がある

Slide 15

Slide 15 text

© 2025 Wantedly, Inc. Apollo Sandbox 前提 おもむろに叩くと当然落ちる

Slide 16

Slide 16 text

© 2025 Wantedly, Inc. Apollo Sandbox 前提 Apollo Sandbox は認証情報を自動で取得しない 毎回手動でトークンをアプリ側からコピー & ペーストする必要がある

Slide 17

Slide 17 text

© 2025 Wantedly, Inc. Apollo Sandbox 普段どうしているか 1. トークンをコピー

Slide 18

Slide 18 text

© 2025 Wantedly, Inc. Apollo Sandbox 普段どうしているか 1. トークンをコピー 2. 貼り付け

Slide 19

Slide 19 text

© 2025 Wantedly, Inc. Apollo Sandbox 問題はなにか? トークンは数時間ごとに切れる

Slide 20

Slide 20 text

© 2025 Wantedly, Inc. Apollo Sandbox どうなるか? 1. API を叩く

Slide 21

Slide 21 text

© 2025 Wantedly, Inc. Apollo Sandbox どうなるか? 1. API を叩く Not authenticated

Slide 22

Slide 22 text

© 2025 Wantedly, Inc. Apollo Sandbox どうなるか? 1. API を叩く Not authenticated 2. え?なんで?

Slide 23

Slide 23 text

© 2025 Wantedly, Inc. Apollo Sandbox どうなるか? 1. API を叩く Not authenticated 2. え?なんで? あ、トークン切れてた …

Slide 24

Slide 24 text

© 2025 Wantedly, Inc. Apollo Sandbox どうなるか? 1. API を叩く Not authenticated 2. え?なんで? あ、トークン切れてた … 3. アプリ側で新しいトークンをコピー & ペースト

Slide 25

Slide 25 text

© 2025 Wantedly, Inc. Apollo Sandbox どうなるか? 1. API を叩く Not authenticated 2. え?なんで? あ、トークン切れてた … 3. アプリ側で新しいトークンをコピー & ペースト また数時間後に繰り返す‥

Slide 26

Slide 26 text

© 2025 Wantedly, Inc. Apollo Sandbox どうなるか? 1. API を叩く Not authenticated 2. え?なんで? あ、トークン切れてた … 3. アプリ側で新しいトークンをコピー & ペースト また数時間後に繰り返す‥ ストレスフル

Slide 27

Slide 27 text

© 2025 Wantedly, Inc. Apollo Sandbox ストレスフル 最初は気にならないが毎回コピペするのは正直しんどい 数時間ごとにリフレッシュ?開発者は人間だぞ 手動更新?そんなのやだよ〜

Slide 28

Slide 28 text

© 2025 Wantedly, Inc. Apollo Sandbox どうするか テクノロジーの力で 完全自動化するぞ

Slide 29

Slide 29 text

© 2025 Wantedly, Inc. 話すこと 背景 課題 解決策 Wantedly Hire アプリケーションについて Access token 管理と期限について Apollo Sandbox ストレスの原因 解決策とその評価 失敗した作戦一覧 最終解決策 demo を交えて紹介

Slide 30

Slide 30 text

© 2025 Wantedly, Inc. 解決策 結果 感想 サブドメイン Cookie 共有 Apollo Sandbox にログイン機能 Chrome Extension cookies API Chrome Extension declarativeNetRequest API 解決策とその評価 失敗した作戦一覧

Slide 31

Slide 31 text

© 2025 Wantedly, Inc. サブドメイン Cookie 共有 各環境の URL hire.wantedly.com 参照元: Wantedly Hire gql.example.wantedly.com 参照先: Apollo Sandbox

Slide 32

Slide 32 text

© 2025 Wantedly, Inc. サブドメイン Cookie 共有 Cookie の送信先の定義 Domain 属性は Cookie を受信できるサーバーを指定する Domain=wantedly.com -> fizz.wantedly.com や buzz.wantedly.com に設定できる 指定されたサーバーとサブドメインで Cookie が利用可能 buzz.wantedly.com は fizz.buzz.wantedly.com には設定できない 自分が管理するドメイン or その親に対してのみ設定できる

Slide 33

Slide 33 text

© 2025 Wantedly, Inc. サブドメイン Cookie 共有 方法 hire.wantedly.com で Domain 属性に wantedly.com を定義

Slide 34

Slide 34 text

© 2025 Wantedly, Inc. サブドメイン Cookie 共有 断念した理由 トークンのスコープ管理 意図しないサービスでトークンが利用されるリスクがある JWT に変換された Hire のトークン 大きすぎて他のサービスで cookie の最大データ容量を超えてしまう

Slide 35

Slide 35 text

© 2025 Wantedly, Inc. 解決策 結果 理由 サブドメイン Cookie 共有 セキュリティリスクが高く 他のプロダクトに影響がでる Apollo Sandbox にログイン機能 Chrome Extension cookies API Chrome Extension declarativeNetRequest API 解決策とその評価 失敗した作戦一覧

Slide 36

Slide 36 text

© 2025 Wantedly, Inc. Apollo Sandbox にログイン機能 Apollo Sandbox にログイン機能を実装 簡単なもの 例えばメアド + パスワード を Basic 認証で mutation をサーバーサイドで実行 方法

Slide 37

Slide 37 text

© 2025 Wantedly, Inc. Apollo Sandbox にログイン機能 断念した理由 Google 認証の対応が大変 コスト高い 二重管理になる もはやアプリ本体の認証と変わらない

Slide 38

Slide 38 text

© 2025 Wantedly, Inc. 解決策 結果 理由 サブドメイン Cookie 共有 セキュリティリスクが高く 他のプロダクトに影響がでる Apollo Sandbox にログイン機能 認証フローの二重管理が必要 Google認証の対応が複雑 Chrome Extension webRequest API Chrome Extension cookies API 解決策とその評価 失敗した作戦一覧

Slide 39

Slide 39 text

© 2025 Wantedly, Inc. Chrome Extension 使えそうな API webRequest API cookies API

Slide 40

Slide 40 text

© 2025 Wantedly, Inc. Chrome Extension 使えそうな API webRequest API cookies API なにができる? ブラウザで行われる HTTP リクエストを インターセプトして任意の操作を行える強力な API ● リクエストのキャンセル ● リクエストのリダイレクト ● リクエストヘッダーの変更 ● レスポンスの変更 ● etc. なんでもできてしまう

Slide 41

Slide 41 text

© 2025 Wantedly, Inc. Chrome Extension 使えそうな API webRequest API cookies API なにができる? ブラウザ内で保存されている cookies を操作するための API ● 基本的な CRUD 操作 ● Cookie の変更をリスナーで監視 許可されたドメインに関連する Cookie しか操作できない 制約事項 拡張機能の permissions フィールドで適切なドメインを指定する

Slide 42

Slide 42 text

© 2025 Wantedly, Inc. Chrome Extension まとめ webRequest API HTTP リクエストやレスポンスを操作できる cookies API ブラウザ内で保存されている cookie を操作できる

Slide 43

Slide 43 text

© 2025 Wantedly, Inc. Chrome Extension webRequest API を使ってみよう webRequest API HTTP リクエストやレスポンスを操作できる cookies API ブラウザ内で保存されている cookie を操作できる

Slide 44

Slide 44 text

© 2025 Wantedly, Inc. Chrome Extension webRequest API の利用は難しそう Manifest V3 の制限 特定の条件を満たさないと webRequest API は利用できない 代替として declarativeNetRequest があるが‥ 名前の通り宣言的 API なので動的にリクエスト変更をするのができなさそう

Slide 45

Slide 45 text

© 2025 Wantedly, Inc. 解決策 結果 理由 サブドメイン Cookie 共有 セキュリティリスクが高く 他のプロダクトに影響がでる Apollo Sandbox にログイン機能 認証フローの二重管理が必要 Google認証の対応が複雑 Chrome Extension webRequest API Manifest V3 にやられた Chrome Extension cookies API 解決策とその評価 失敗した作戦一覧

Slide 46

Slide 46 text

© 2025 Wantedly, Inc. Chrome Extension cookies API を使ってみよう webRequest API HTTP リクエストやレスポンスを操作できる cookies API ブラウザ内で保存されている cookie を操作できる

Slide 47

Slide 47 text

© 2025 Wantedly, Inc. Chrome Extension Wantedly Hire から Apollo Sandbox に cookie をセット もちろん permissions フィールドで適切なドメインを指定する Apollo Sandbox で通信時に HTTP Header にトークンを乗せる 何らかの方法でリクエストに HTTP Header にセットするようにする cookies API 方法

Slide 48

Slide 48 text

© 2025 Wantedly, Inc. Chrome Extension cookies API 方法 getCookies 実装 setCookies 実装 トークンを乗せる

Slide 49

Slide 49 text

© 2025 Wantedly, Inc. Chrome Extension cookies API 方法 getCookies 実装 setCookies 実装 トークンを乗せる // background.ts const appRouter = t.router({ getCookies: t.procedure .input(z.object({ domain: z.string(), environment: z.enum(APP_ENV) })) .query(async ({ input }) => { const cookie = await chrome.cookies.get({ name: getConfigByEnv(input.environment).accessTokenKey, url: `https://${input.domain}`, }); if (cookie === null) return { success: false, tokens: "" }; return { success: true, tokens: cookie.value }; }), });

Slide 50

Slide 50 text

© 2025 Wantedly, Inc. Chrome Extension cookies API 方法 getCookies 実装 setCookies 実装 トークンを乗せる // background.ts setCookies: t.procedure .input( z.object({ domain: z.string(), cookies: z.object({ name: z.string(), value: z.string() }), environment: z.enum(APP_ENV), }) ) .mutation(async ({ input }) => { await chrome.cookies.set({ name: getConfigByEnv(input.environment).accessTokenKey, value: input.cookies.value, url: `https://${input.domain}`, }); }),

Slide 51

Slide 51 text

© 2025 Wantedly, Inc. Chrome Extension cookies API 方法 getCookies 実装 setCookies 実装 トークンを乗せる 2パターンある 1. Apollo Sandbox 本体に手を加える 2. Chrome Extension だけで解決する

Slide 52

Slide 52 text

© 2025 Wantedly, Inc. Chrome Extension Apollo Sandbox 本体に手を加える こんな感じのスクリプトで fetch 関数をオーバーライド const originalFetch = window.fetch; window.fetch = async (input, init = {}) => { const modifiedHeaders = new Headers(init.headers); modifiedHeaders.set("authorization", "xxx"); const modifiedInit = { ...init, headers: modifiedHeaders }; return originalFetch(input, modifiedInit); };

Slide 53

Slide 53 text

© 2025 Wantedly, Inc. Chrome Extension 無事動いた しかし Chrome Extension ありきの実装 Apollo Sandbox 本体に手を加える

Slide 54

Slide 54 text

© 2025 Wantedly, Inc. Chrome Extension 背景を知らない人間が見た時に必ず疑問が浮かぶ なぜ Chrome Extension ありきの実装を入れているのか Apollo Sandbox 本体に手を加える この方法は最終手段にしたい できれば他の方法で解決したい

Slide 55

Slide 55 text

© 2025 Wantedly, Inc. Chrome Extension cookies API 方法 getCookies 実装 setCookies 実装 トークンを乗せる 2パターンある 1. Apollo Sandbox 本体に手を加える 2. Chrome Extension だけで解決する

Slide 56

Slide 56 text

© 2025 Wantedly, Inc. Chrome Extension Apollo Sandbox 本体に手を加える const originalFetch = window.fetch; window.fetch = async (input, init = {}) => { const modifiedHeaders = new Headers(init.headers); modifiedHeaders.set("authorization", "xxx"); const modifiedInit = { ...init, headers: modifiedHeaders }; return originalFetch(input, modifiedInit); }; タグ で先程のスクリプトを Apollo Sandbox に Chrome Extension を使って挿入する

Slide 57

Slide 57 text

© 2025 Wantedly, Inc. Chrome Extension 無事成功したが少しやり方がハッキーすぎる Chrome Extension だけで解決する この方法も最終手段にしたい できれば他の方法で解決したい

Slide 58

Slide 58 text

© 2025 Wantedly, Inc. 解決策 結果 理由 サブドメイン Cookie 共有 セキュリティリスクが高く 他のプロダクトに影響がでる Apollo Sandbox にログイン機能 認証フローの二重管理が必要 Google認証の対応が複雑 Chrome Extension webRequest API Manifest V3 にやられた Chrome Extension cookies API できなくはないが 実装がゴリ押し過ぎる 解決策とその評価 失敗した作戦一覧

Slide 59

Slide 59 text

© 2025 Wantedly, Inc. 話すこと 背景 課題 解決策 Wantedly Hire アプリケーションについて Access token 管理と期限について Apollo Sandbox ストレスの原因 解決策とその評価 失敗した作戦一覧 最終解決策 demo を交えて紹介

Slide 60

Slide 60 text

© 2025 Wantedly, Inc. Chrome Extension webRequest API の利用は難しそう Manifest V3 の制限 特定の条件を満たさないと webRequest API は利用できない 代替として declarativeNetRequest があるが‥ 名前の通り宣言的 API なので動的にリクエスト変更をするのができなさそう declarativeNetRequest に updateDynamicRules がある

Slide 61

Slide 61 text

© 2025 Wantedly, Inc. Chrome Extension updateDynamicRules 動的ルールを追加・削除できるメソッド declarativeNetRequest API リクエストのヘッダーを事前に決めたルールで変更可能 JavaScript で動的に処理できない

Slide 62

Slide 62 text

© 2025 Wantedly, Inc. Chrome Extension declarativeNetRequest API chrome.declarativeNetRequest.updateDynamicRules({ removeRuleIds: [1], addRules: [ { id: 1, priority: 1, action: { type: chrome.declarativeNetRequest.RuleActionType.MODIFY_HEADERS, requestHeaders: [ { header: "Authorization", operation: chrome.declarativeNetRequest.HeaderOperation.SET, value: `Bearer ${input.accessToken}`, }, ], }, condition: { urlFilter: `https://gql.example.wantedly.com/graphql`, resourceTypes: [ chrome.declarativeNetRequest.ResourceType.XMLHTTPREQUEST, ], }, }, ], }); 事前にルールを決める 〇〇にリクエスト送る時はヘッダーつけてね

Slide 63

Slide 63 text

© 2025 Wantedly, Inc. Demonstration 最終解決策

Slide 64

Slide 64 text

© 2025 Wantedly, Inc. 最終解決策

Slide 65

Slide 65 text

© 2025 Wantedly, Inc. デザイン

Slide 66

Slide 66 text

© 2025 Wantedly, Inc. 認証トークンの手動更新から 解放される日が来た…! まとめ

Slide 67

Slide 67 text

© 2025 Wantedly, Inc. 解決策 結果 理由 サブドメイン Cookie 共有 セキュリティリスクが高く 他のプロダクトに影響がでる Apollo Sandbox にログイン機能 認証フローの二重管理が必要 Google認証の対応が複雑 Chrome Extension webRequest API Manifest V3 にやられた Chrome Extension API cookies + declarativeNetRequest 最強 まとめ Chrome Extension 最強!

Slide 68

Slide 68 text

© 2025 Wantedly, Inc. まとめ 失敗の数だけ知識が増える (らしい)

Slide 69

Slide 69 text

© 2025 Wantedly, Inc. もうトークンに苦しむな まとめ

Slide 70

Slide 70 text

© 2025 Wantedly, Inc. 話したこと 背景 課題 解決策 Wantedly Hire アプリケーションについて Access token 管理と期限について Apollo Sandbox ストレスの原因 解決策とその評価 失敗した作戦一覧 最終解決策 demo を交えて紹介