[{"data":1,"prerenderedAt":2490},["ShallowReactive",2],{"content-/google-oauth-setup-guide":3,"all-pages-for-dir":2470,"related-/google-oauth-setup-guide":2471,"og-image-/google-oauth-setup-guide":2489},{"id":4,"title":5,"body":6,"category":2455,"concepts":2455,"description":2456,"extension":2457,"meta":2458,"navigation":595,"ogImage":2455,"path":2459,"project_name":2455,"published":2460,"publishedAt":2461,"seo":2462,"source":2455,"stem":2463,"tags":2464,"todo":2455,"unpublished":2460,"updatedAt":2461,"__hash__":2469},"pages/2025-12/2025-12-11/google-oauth-setup-guide.md","Google OAuth 設定ガイド",{"type":7,"value":8,"toc":2414},"minimark",[9,13,28,31,35,38,40,44,49,70,72,76,80,144,146,150,154,159,352,356,381,385,390,416,418,422,426,510,514,517,523,528,548,550,554,558,563,603,607,665,669,741,743,747,751,977,981,1239,1465,1467,1471,1475,1711,1714,2036,2038,2042,2046,2049,2078,2082,2085,2115,2117,2121,2125,2131,2137,2165,2171,2175,2180,2184,2192,2196,2201,2205,2216,2219,2224,2228,2328,2330,2334,2340,2342,2345,2402,2404,2410],[10,11,5],"h1",{"id":12},"google-oauth-設定ガイド",[14,15,16,20,21,24,27],"p",{},[17,18,19],"strong",{},"対象",": Chat Story サービスへの Google ログイン実装",[22,23],"br",{},[17,25,26],{},"作成日",": 2025年12月11日",[29,30],"hr",{},[32,33,34],"h2",{"id":34},"概要",[14,36,37],{},"このドキュメントでは、Google Cloud ConsoleでOAuth 2.0認証情報（Client ID / Client Secret）を取得しBetter Authと連携するまでの手順を解説する。",[29,39],{},[32,41,43],{"id":42},"_1-google-cloud-console-へのアクセス","1. Google Cloud Console へのアクセス",[45,46,48],"h3",{"id":47},"step-1-google-cloud-console-を開く","Step 1: Google Cloud Console を開く",[50,51,52,67],"ol",{},[53,54,55,56],"li",{},"以下のURLにアクセス",[57,58,63],"pre",{"className":59,"code":61,"language":62},[60],"language-text","https://console.cloud.google.com/\n","text",[64,65,61],"code",{"__ignoreMap":66},"",[53,68,69],{},"Googleアカウントでログイン（まだの場合）",[29,71],{},[32,73,75],{"id":74},"_2-プロジェクトの作成","2. プロジェクトの作成",[45,77,79],{"id":78},"step-2-新規プロジェクト作成","Step 2: 新規プロジェクト作成",[50,81,82,89,95,136,141],{},[53,83,84,85,88],{},"画面上部の ",[17,86,87],{},"プロジェクト選択"," ドロップダウンをクリック",[53,90,91,94],{},[17,92,93],{},"「新しいプロジェクト」"," をクリック",[53,96,97,98],{},"プロジェクト情報を入力：",[99,100,101,114],"table",{},[102,103,104],"thead",{},[105,106,107,111],"tr",{},[108,109,110],"th",{},"項目",[108,112,113],{},"入力例",[115,116,117,128],"tbody",{},[105,118,119,123],{},[120,121,122],"td",{},"プロジェクト名",[120,124,125],{},[64,126,127],{},"chat-story",[105,129,130,133],{},[120,131,132],{},"場所",[120,134,135],{},"「組織なし」または所属組織",[53,137,138,94],{},[17,139,140],{},"「作成」",[53,142,143],{},"作成完了後、そのプロジェクトが選択されていることを確認",[29,145],{},[32,147,149],{"id":148},"_3-oauth-同意画面の設定","3. OAuth 同意画面の設定",[45,151,153],{"id":152},"step-3-oauth-同意画面を構成","Step 3: OAuth 同意画面を構成",[14,155,156],{},[17,157,158],{},"※ この設定は必須。先にこれをしないと認証情報を作成できない。",[50,160,161,172,228,287,335,347],{},[53,162,163,164,167,168,171],{},"左側メニューから ",[17,165,166],{},"「APIとサービス」"," → ",[17,169,170],{},"「OAuth 同意画面」"," を選択",[53,173,174,177,178,219,221,222,225,226],{},[17,175,176],{},"User Type"," を選択：",[99,179,180,193],{},[102,181,182],{},[105,183,184,187,190],{},[108,185,186],{},"タイプ",[108,188,189],{},"説明",[108,191,192],{},"推奨",[115,194,195,208],{},[105,196,197,202,205],{},[120,198,199],{},[17,200,201],{},"外部",[120,203,204],{},"すべてのGoogleアカウントが対象",[120,206,207],{},"◯ 一般公開サービス向け",[105,209,210,213,216],{},[120,211,212],{},"内部",[120,214,215],{},"Google Workspace組織内のみ",[120,217,218],{},"社内ツール向け",[22,220],{},"→ ",[17,223,224],{},"「外部」"," を選択して ",[17,227,140],{},[53,229,230,233,234],{},[17,231,232],{},"アプリ情報"," を入力：",[99,235,236,248],{},[102,237,238],{},[105,239,240,242,245],{},[108,241,110],{},[108,243,244],{},"入力内容",[108,246,247],{},"例",[115,249,250,263,276],{},[105,251,252,255,258],{},[120,253,254],{},"アプリ名",[120,256,257],{},"サービス名",[120,259,260],{},[64,261,262],{},"Chat Story",[105,264,265,268,271],{},[120,266,267],{},"ユーザーサポートメール",[120,269,270],{},"問い合わせ先",[120,272,273],{},[64,274,275],{},"support@example.com",[105,277,278,281,284],{},[120,279,280],{},"アプリのロゴ",[120,282,283],{},"（任意）ロゴ画像",[120,285,286],{},"-",[53,288,289,292,293],{},[17,290,291],{},"アプリのドメイン","（任意、本番環境用）：",[99,294,295,303],{},[102,296,297],{},[105,298,299,301],{},[108,300,110],{},[108,302,244],{},[115,304,305,315,325],{},[105,306,307,310],{},[120,308,309],{},"アプリケーションのホームページ",[120,311,312],{},[64,313,314],{},"https://chat-story.number55number55.workers.dev",[105,316,317,320],{},[120,318,319],{},"プライバシーポリシーのリンク",[120,321,322],{},[64,323,324],{},"https://chat-story.../privacy",[105,326,327,330],{},[120,328,329],{},"利用規約のリンク",[120,331,332],{},[64,333,334],{},"https://chat-story.../terms",[53,336,337,340,341],{},[17,338,339],{},"デベロッパーの連絡先情報","：",[342,343,344],"ul",{},[53,345,346],{},"メールアドレスを入力",[53,348,349,94],{},[17,350,351],{},"「保存して次へ」",[45,353,355],{"id":354},"step-4-スコープの設定","Step 4: スコープの設定",[50,357,358,363,372,377],{},[53,359,360,94],{},[17,361,362],{},"「スコープを追加または削除」",[53,364,365,366],{},"以下のスコープを選択：",[57,367,370],{"className":368,"code":369,"language":62},[60],"✅ .../auth/userinfo.email    （メールアドレス取得）\n✅ .../auth/userinfo.profile  （プロフィール情報取得）\n✅ openid                      （OpenID Connect）\n",[64,371,369],{"__ignoreMap":66},[53,373,374,94],{},[17,375,376],{},"「更新」",[53,378,379,94],{},[17,380,351],{},[45,382,384],{"id":383},"step-5-テストユーザーの追加開発中のみ","Step 5: テストユーザーの追加（開発中のみ）",[14,386,387],{},[17,388,389],{},"※ 公開ステータスが「テスト」の間は、ここに登録したユーザーのみログイン可能。",[50,391,392,397,406,410],{},[53,393,394,94],{},[17,395,396],{},"「+ ADD USERS」",[53,398,399,400],{},"テストに使用するGoogleアカウントのメールアドレスを追加",[57,401,404],{"className":402,"code":403,"language":62},[60],"例: your-email@gmail.com\n",[64,405,403],{"__ignoreMap":66},[53,407,408,94],{},[17,409,351],{},[53,411,412,413],{},"概要を確認して ",[17,414,415],{},"「ダッシュボードに戻る」",[29,417],{},[32,419,421],{"id":420},"_4-oauth-認証情報の作成","4. OAuth 認証情報の作成",[45,423,425],{"id":424},"step-6-認証情報を作成","Step 6: 認証情報を作成",[50,427,428,435,441,446,457,468,480,506],{},[53,429,163,430,167,432,171],{},[17,431,166],{},[17,433,434],{},"「認証情報」",[53,436,437,438,94],{},"上部の ",[17,439,440],{},"「+ 認証情報を作成」",[53,442,443,171],{},[17,444,445],{},"「OAuth クライアント ID」",[53,447,448,177,451],{},[17,449,450],{},"アプリケーションの種類",[57,452,455],{"className":453,"code":454,"language":62},[60],"ウェブ アプリケーション\n",[64,456,454],{"__ignoreMap":66},[53,458,459,233,462],{},[17,460,461],{},"名前",[57,463,466],{"className":464,"code":465,"language":62},[60],"Chat Story Web Client\n",[64,467,465],{"__ignoreMap":66},[53,469,470,473,474],{},[17,471,472],{},"承認済みの JavaScript 生成元","（開発環境 + 本番環境）：",[57,475,478],{"className":476,"code":477,"language":62},[60],"http://localhost:3000\nhttp://localhost:5173\nhttps://chat-story.number55number55.workers.dev\n",[64,479,477],{"__ignoreMap":66},[53,481,482,485,486,492],{},[17,483,484],{},"承認済みのリダイレクト URI","（重要！）：",[57,487,490],{"className":488,"code":489,"language":62},[60],"http://localhost:3000/api/auth/callback/google\nhttp://localhost:5173/api/auth/callback/google\nhttps://chat-story.number55number55.workers.dev/api/auth/callback/google\n",[64,491,489],{"__ignoreMap":66},[493,494,495],"blockquote",{},[14,496,497,498,501,502,505],{},"⚠️ ",[17,499,500],{},"注意",": Better Authのデフォルトコールバックパスは ",[64,503,504],{},"/api/auth/callback/google","。\nカスタマイズしている場合は適宜変更すること。",[53,507,508,94],{},[17,509,140],{},[45,511,513],{"id":512},"step-7-認証情報を取得","Step 7: 認証情報を取得",[14,515,516],{},"作成完了すると、以下の情報が表示されます：",[57,518,521],{"className":519,"code":520,"language":62},[60],"┌─────────────────────────────────────────────────────┐\n│  OAuth クライアントを作成しました                      │\n│                                                      │\n│  クライアント ID:                                     │\n│  123456789-abcdefg.apps.googleusercontent.com       │\n│                                                      │\n│  クライアント シークレット:                           │\n│  GOCSPX-xxxxxxxxxxxxxxxxxxxxxxxx                    │\n│                                                      │\n│  [JSON をダウンロード]  [OK]                          │\n└─────────────────────────────────────────────────────┘\n",[64,522,520],{"__ignoreMap":66},[14,524,525],{},[17,526,527],{},"この情報を安全な場所に保存してください！",[342,529,530,540],{},[53,531,532,535,536,539],{},[17,533,534],{},"Client ID",": ",[64,537,538],{},"GOOGLE_CLIENT_ID"," として使用",[53,541,542,535,545,539],{},[17,543,544],{},"Client Secret",[64,546,547],{},"GOOGLE_CLIENT_SECRET",[29,549],{},[32,551,553],{"id":552},"_5-環境変数の設定","5. 環境変数の設定",[45,555,557],{"id":556},"cloudflare-workers-の場合","Cloudflare Workers の場合",[559,560,562],"h4",{"id":561},"方法1-wranglertoml-に記載開発用","方法1: wrangler.toml に記載（開発用）",[57,564,568],{"className":565,"code":566,"language":567,"meta":66,"style":66},"language-toml shiki shiki-themes vitesse-light vitesse-light","# wrangler.toml\n[vars]\nGOOGLE_CLIENT_ID = \"123456789-abcdefg.apps.googleusercontent.com\"\n\n# シークレットは vars に書かない！\n","toml",[64,569,570,578,584,590,597],{"__ignoreMap":66},[571,572,575],"span",{"class":573,"line":574},"line",1,[571,576,577],{},"# wrangler.toml\n",[571,579,581],{"class":573,"line":580},2,[571,582,583],{},"[vars]\n",[571,585,587],{"class":573,"line":586},3,[571,588,589],{},"GOOGLE_CLIENT_ID = \"123456789-abcdefg.apps.googleusercontent.com\"\n",[571,591,593],{"class":573,"line":592},4,[571,594,596],{"emptyLinePlaceholder":595},true,"\n",[571,598,600],{"class":573,"line":599},5,[571,601,602],{},"# シークレットは vars に書かない！\n",[559,604,606],{"id":605},"方法2-wrangler-cli-でシークレット設定推奨","方法2: Wrangler CLI でシークレット設定（推奨）",[57,608,612],{"className":609,"code":610,"language":611,"meta":66,"style":66},"language-bash shiki shiki-themes vitesse-light vitesse-light","# Client Secret を安全に設定\nnpx wrangler secret put GOOGLE_CLIENT_SECRET\n# プロンプトが出たら値を入力\n\n# 確認\nnpx wrangler secret list\n","bash",[64,613,614,620,639,644,648,653],{"__ignoreMap":66},[571,615,616],{"class":573,"line":574},[571,617,619],{"class":618},"sxvE3","# Client Secret を安全に設定\n",[571,621,622,626,630,633,636],{"class":573,"line":580},[571,623,625],{"class":624},"senZ8","npx",[571,627,629],{"class":628},"sdGka"," wrangler",[571,631,632],{"class":628}," secret",[571,634,635],{"class":628}," put",[571,637,638],{"class":628}," GOOGLE_CLIENT_SECRET\n",[571,640,641],{"class":573,"line":586},[571,642,643],{"class":618},"# プロンプトが出たら値を入力\n",[571,645,646],{"class":573,"line":592},[571,647,596],{"emptyLinePlaceholder":595},[571,649,650],{"class":573,"line":599},[571,651,652],{"class":618},"# 確認\n",[571,654,656,658,660,662],{"class":573,"line":655},6,[571,657,625],{"class":624},[571,659,629],{"class":628},[571,661,632],{"class":628},[571,663,664],{"class":628}," list\n",[559,666,668],{"id":667},"方法3-cloudflare-dashboard-から設定","方法3: Cloudflare Dashboard から設定",[50,670,671,680,686,695],{},[53,672,673,679],{},[674,675,676],"a",{"href":676,"rel":677},"https://dash.cloudflare.com/",[678],"nofollow"," にアクセス",[53,681,682,685],{},[17,683,684],{},"Workers & Pages"," → 対象のWorker を選択",[53,687,688,167,691,694],{},[17,689,690],{},"Settings",[17,692,693],{},"Variables"," タブ",[53,696,697,700,701],{},[17,698,699],{},"Environment Variables"," セクションで追加：",[99,702,703,716],{},[102,704,705],{},[105,706,707,710,713],{},[108,708,709],{},"Variable name",[108,711,712],{},"Value",[108,714,715],{},"Encrypt",[115,717,718,728],{},[105,719,720,722,725],{},[120,721,538],{},[120,723,724],{},"123456789-xxx.apps.googleusercontent.com",[120,726,727],{},"No",[105,729,730,732,735],{},[120,731,547],{},[120,733,734],{},"GOCSPX-xxx",[120,736,737,740],{},[17,738,739],{},"Yes"," ✅",[29,742],{},[32,744,746],{"id":745},"_6-better-auth-での設定","6. Better Auth での設定",[45,748,750],{"id":749},"authts-の設定","auth.ts の設定",[57,752,756],{"className":753,"code":754,"language":755,"meta":66,"style":66},"language-typescript shiki shiki-themes vitesse-light vitesse-light","import { betterAuth } from \"better-auth\";\n\nexport const auth = betterAuth({\n  database: /* your database adapter */,\n  \n  // メール/パスワード認証\n  emailAndPassword: {\n    enabled: true,\n  },\n  \n  // Google OAuth\n  socialProviders: {\n    google: {\n      clientId: process.env.GOOGLE_CLIENT_ID as string,\n      clientSecret: process.env.GOOGLE_CLIENT_SECRET as string,\n      // オプション: 追加スコープ\n      // scope: [\"email\", \"profile\", \"openid\"],\n    },\n  },\n});\n","typescript",[64,757,758,791,795,815,829,834,839,848,861,867,872,878,886,894,924,948,954,960,966,971],{"__ignoreMap":66},[571,759,760,764,768,772,775,778,782,785,788],{"class":573,"line":574},[571,761,763],{"class":762},"sHkkW","import",[571,765,767],{"class":766},"shFtX"," {",[571,769,771],{"class":770},"s4oTP"," betterAuth",[571,773,774],{"class":766}," }",[571,776,777],{"class":762}," from",[571,779,781],{"class":780},"sMJiu"," \"",[571,783,784],{"class":628},"better-auth",[571,786,787],{"class":780},"\"",[571,789,790],{"class":766},";\n",[571,792,793],{"class":573,"line":580},[571,794,596],{"emptyLinePlaceholder":595},[571,796,797,800,804,807,810,812],{"class":573,"line":586},[571,798,799],{"class":762},"export",[571,801,803],{"class":802},"stQ0i"," const ",[571,805,806],{"class":770},"auth",[571,808,809],{"class":766}," =",[571,811,771],{"class":624},[571,813,814],{"class":766},"({\n",[571,816,817,821,823,826],{"class":573,"line":592},[571,818,820],{"class":819},"sz8Xr","  database",[571,822,535],{"class":766},[571,824,825],{"class":618},"/* your database adapter */",[571,827,828],{"class":766},",\n",[571,830,831],{"class":573,"line":599},[571,832,833],{"class":766},"  \n",[571,835,836],{"class":573,"line":655},[571,837,838],{"class":618},"  // メール/パスワード認証\n",[571,840,842,845],{"class":573,"line":841},7,[571,843,844],{"class":819},"  emailAndPassword",[571,846,847],{"class":766},": {\n",[571,849,851,854,856,859],{"class":573,"line":850},8,[571,852,853],{"class":819},"    enabled",[571,855,535],{"class":766},[571,857,858],{"class":762},"true",[571,860,828],{"class":766},[571,862,864],{"class":573,"line":863},9,[571,865,866],{"class":766},"  },\n",[571,868,870],{"class":573,"line":869},10,[571,871,833],{"class":766},[571,873,875],{"class":573,"line":874},11,[571,876,877],{"class":618},"  // Google OAuth\n",[571,879,881,884],{"class":573,"line":880},12,[571,882,883],{"class":819},"  socialProviders",[571,885,847],{"class":766},[571,887,889,892],{"class":573,"line":888},13,[571,890,891],{"class":819},"    google",[571,893,847],{"class":766},[571,895,897,900,902,905,908,911,913,915,918,922],{"class":573,"line":896},14,[571,898,899],{"class":819},"      clientId",[571,901,535],{"class":766},[571,903,904],{"class":770},"process",[571,906,907],{"class":766},".",[571,909,910],{"class":770},"env",[571,912,907],{"class":766},[571,914,538],{"class":770},[571,916,917],{"class":762}," as",[571,919,921],{"class":920},"sSkh3"," string",[571,923,828],{"class":766},[571,925,927,930,932,934,936,938,940,942,944,946],{"class":573,"line":926},15,[571,928,929],{"class":819},"      clientSecret",[571,931,535],{"class":766},[571,933,904],{"class":770},[571,935,907],{"class":766},[571,937,910],{"class":770},[571,939,907],{"class":766},[571,941,547],{"class":770},[571,943,917],{"class":762},[571,945,921],{"class":920},[571,947,828],{"class":766},[571,949,951],{"class":573,"line":950},16,[571,952,953],{"class":618},"      // オプション: 追加スコープ\n",[571,955,957],{"class":573,"line":956},17,[571,958,959],{"class":618},"      // scope: [\"email\", \"profile\", \"openid\"],\n",[571,961,963],{"class":573,"line":962},18,[571,964,965],{"class":766},"    },\n",[571,967,969],{"class":573,"line":968},19,[571,970,866],{"class":766},[571,972,974],{"class":573,"line":973},20,[571,975,976],{"class":766},"});\n",[45,978,980],{"id":979},"cloudflare-workers-hono-での設定","Cloudflare Workers (Hono) での設定",[57,982,984],{"className":753,"code":983,"language":755,"meta":66,"style":66},"// src/index.ts\nimport { Hono } from \"hono\";\nimport { auth } from \"./auth\";\n\ntype Bindings = {\n  GOOGLE_CLIENT_ID: string;\n  GOOGLE_CLIENT_SECRET: string;\n  DB: D1Database;\n};\n\nconst app = new Hono\u003C{ Bindings: Bindings }>();\n\n// Better Auth のハンドラーを設定\napp.on([\"GET\", \"POST\"], \"/api/auth/*\", (c) => {\n  return auth.handler(c.req.raw);\n});\n\nexport default app;\n",[64,985,986,991,1013,1035,1039,1052,1064,1075,1087,1092,1096,1125,1129,1134,1189,1219,1223,1227],{"__ignoreMap":66},[571,987,988],{"class":573,"line":574},[571,989,990],{"class":618},"// src/index.ts\n",[571,992,993,995,997,1000,1002,1004,1006,1009,1011],{"class":573,"line":580},[571,994,763],{"class":762},[571,996,767],{"class":766},[571,998,999],{"class":770}," Hono",[571,1001,774],{"class":766},[571,1003,777],{"class":762},[571,1005,781],{"class":780},[571,1007,1008],{"class":628},"hono",[571,1010,787],{"class":780},[571,1012,790],{"class":766},[571,1014,1015,1017,1019,1022,1024,1026,1028,1031,1033],{"class":573,"line":586},[571,1016,763],{"class":762},[571,1018,767],{"class":766},[571,1020,1021],{"class":770}," auth",[571,1023,774],{"class":766},[571,1025,777],{"class":762},[571,1027,781],{"class":780},[571,1029,1030],{"class":628},"./auth",[571,1032,787],{"class":780},[571,1034,790],{"class":766},[571,1036,1037],{"class":573,"line":592},[571,1038,596],{"emptyLinePlaceholder":595},[571,1040,1041,1044,1047,1049],{"class":573,"line":599},[571,1042,1043],{"class":802},"type",[571,1045,1046],{"class":920}," Bindings",[571,1048,809],{"class":766},[571,1050,1051],{"class":766}," {\n",[571,1053,1054,1057,1059,1062],{"class":573,"line":655},[571,1055,1056],{"class":770},"  GOOGLE_CLIENT_ID",[571,1058,535],{"class":766},[571,1060,1061],{"class":920},"string",[571,1063,790],{"class":766},[571,1065,1066,1069,1071,1073],{"class":573,"line":841},[571,1067,1068],{"class":770},"  GOOGLE_CLIENT_SECRET",[571,1070,535],{"class":766},[571,1072,1061],{"class":920},[571,1074,790],{"class":766},[571,1076,1077,1080,1082,1085],{"class":573,"line":850},[571,1078,1079],{"class":770},"  DB",[571,1081,535],{"class":766},[571,1083,1084],{"class":920},"D1Database",[571,1086,790],{"class":766},[571,1088,1089],{"class":573,"line":863},[571,1090,1091],{"class":766},"};\n",[571,1093,1094],{"class":573,"line":869},[571,1095,596],{"emptyLinePlaceholder":595},[571,1097,1098,1101,1104,1106,1109,1112,1115,1117,1119,1122],{"class":573,"line":874},[571,1099,1100],{"class":802},"const ",[571,1102,1103],{"class":770},"app",[571,1105,809],{"class":766},[571,1107,1108],{"class":802}," new ",[571,1110,1111],{"class":624},"Hono",[571,1113,1114],{"class":766},"\u003C{",[571,1116,1046],{"class":770},[571,1118,535],{"class":766},[571,1120,1121],{"class":920},"Bindings",[571,1123,1124],{"class":766}," }>();\n",[571,1126,1127],{"class":573,"line":880},[571,1128,596],{"emptyLinePlaceholder":595},[571,1130,1131],{"class":573,"line":888},[571,1132,1133],{"class":618},"// Better Auth のハンドラーを設定\n",[571,1135,1136,1138,1140,1143,1146,1148,1151,1153,1156,1158,1161,1163,1166,1168,1171,1173,1175,1178,1181,1184,1187],{"class":573,"line":896},[571,1137,1103],{"class":770},[571,1139,907],{"class":766},[571,1141,1142],{"class":624},"on",[571,1144,1145],{"class":766},"([",[571,1147,787],{"class":780},[571,1149,1150],{"class":628},"GET",[571,1152,787],{"class":780},[571,1154,1155],{"class":766},",",[571,1157,781],{"class":780},[571,1159,1160],{"class":628},"POST",[571,1162,787],{"class":780},[571,1164,1165],{"class":766},"],",[571,1167,781],{"class":780},[571,1169,1170],{"class":628},"/api/auth/*",[571,1172,787],{"class":780},[571,1174,1155],{"class":766},[571,1176,1177],{"class":766}," (",[571,1179,1180],{"class":770},"c",[571,1182,1183],{"class":766},")",[571,1185,1186],{"class":766}," =>",[571,1188,1051],{"class":766},[571,1190,1191,1194,1196,1198,1201,1204,1206,1208,1211,1213,1216],{"class":573,"line":926},[571,1192,1193],{"class":762},"  return",[571,1195,1021],{"class":770},[571,1197,907],{"class":766},[571,1199,1200],{"class":624},"handler",[571,1202,1203],{"class":766},"(",[571,1205,1180],{"class":770},[571,1207,907],{"class":766},[571,1209,1210],{"class":770},"req",[571,1212,907],{"class":766},[571,1214,1215],{"class":770},"raw",[571,1217,1218],{"class":766},");\n",[571,1220,1221],{"class":573,"line":950},[571,1222,976],{"class":766},[571,1224,1225],{"class":573,"line":956},[571,1226,596],{"emptyLinePlaceholder":595},[571,1228,1229,1231,1234,1237],{"class":573,"line":962},[571,1230,799],{"class":762},[571,1232,1233],{"class":762}," default",[571,1235,1236],{"class":770}," app",[571,1238,790],{"class":766},[57,1240,1242],{"className":753,"code":1241,"language":755,"meta":66,"style":66},"// src/auth.ts (Cloudflare Workers 用)\nimport { betterAuth } from \"better-auth\";\nimport { D1Adapter } from \"better-auth/adapters/d1\";\n\nexport function createAuth(env: {\n  GOOGLE_CLIENT_ID: string;\n  GOOGLE_CLIENT_SECRET: string;\n  DB: D1Database;\n}) {\n  return betterAuth({\n    database: D1Adapter(env.DB),\n    emailAndPassword: {\n      enabled: true,\n    },\n    socialProviders: {\n      google: {\n        clientId: env.GOOGLE_CLIENT_ID,\n        clientSecret: env.GOOGLE_CLIENT_SECRET,\n      },\n    },\n  });\n}\n",[64,1243,1244,1249,1269,1291,1295,1311,1321,1331,1341,1348,1356,1378,1385,1396,1400,1407,1414,1429,1444,1449,1453,1459],{"__ignoreMap":66},[571,1245,1246],{"class":573,"line":574},[571,1247,1248],{"class":618},"// src/auth.ts (Cloudflare Workers 用)\n",[571,1250,1251,1253,1255,1257,1259,1261,1263,1265,1267],{"class":573,"line":580},[571,1252,763],{"class":762},[571,1254,767],{"class":766},[571,1256,771],{"class":770},[571,1258,774],{"class":766},[571,1260,777],{"class":762},[571,1262,781],{"class":780},[571,1264,784],{"class":628},[571,1266,787],{"class":780},[571,1268,790],{"class":766},[571,1270,1271,1273,1275,1278,1280,1282,1284,1287,1289],{"class":573,"line":586},[571,1272,763],{"class":762},[571,1274,767],{"class":766},[571,1276,1277],{"class":770}," D1Adapter",[571,1279,774],{"class":766},[571,1281,777],{"class":762},[571,1283,781],{"class":780},[571,1285,1286],{"class":628},"better-auth/adapters/d1",[571,1288,787],{"class":780},[571,1290,790],{"class":766},[571,1292,1293],{"class":573,"line":592},[571,1294,596],{"emptyLinePlaceholder":595},[571,1296,1297,1299,1302,1305,1307,1309],{"class":573,"line":599},[571,1298,799],{"class":762},[571,1300,1301],{"class":802}," function",[571,1303,1304],{"class":624}," createAuth",[571,1306,1203],{"class":766},[571,1308,910],{"class":770},[571,1310,847],{"class":766},[571,1312,1313,1315,1317,1319],{"class":573,"line":655},[571,1314,1056],{"class":770},[571,1316,535],{"class":766},[571,1318,1061],{"class":920},[571,1320,790],{"class":766},[571,1322,1323,1325,1327,1329],{"class":573,"line":841},[571,1324,1068],{"class":770},[571,1326,535],{"class":766},[571,1328,1061],{"class":920},[571,1330,790],{"class":766},[571,1332,1333,1335,1337,1339],{"class":573,"line":850},[571,1334,1079],{"class":770},[571,1336,535],{"class":766},[571,1338,1084],{"class":920},[571,1340,790],{"class":766},[571,1342,1343,1346],{"class":573,"line":863},[571,1344,1345],{"class":766},"})",[571,1347,1051],{"class":766},[571,1349,1350,1352,1354],{"class":573,"line":869},[571,1351,1193],{"class":762},[571,1353,771],{"class":624},[571,1355,814],{"class":766},[571,1357,1358,1361,1363,1366,1368,1370,1372,1375],{"class":573,"line":874},[571,1359,1360],{"class":819},"    database",[571,1362,535],{"class":766},[571,1364,1365],{"class":624},"D1Adapter",[571,1367,1203],{"class":766},[571,1369,910],{"class":770},[571,1371,907],{"class":766},[571,1373,1374],{"class":770},"DB",[571,1376,1377],{"class":766},"),\n",[571,1379,1380,1383],{"class":573,"line":880},[571,1381,1382],{"class":819},"    emailAndPassword",[571,1384,847],{"class":766},[571,1386,1387,1390,1392,1394],{"class":573,"line":888},[571,1388,1389],{"class":819},"      enabled",[571,1391,535],{"class":766},[571,1393,858],{"class":762},[571,1395,828],{"class":766},[571,1397,1398],{"class":573,"line":896},[571,1399,965],{"class":766},[571,1401,1402,1405],{"class":573,"line":926},[571,1403,1404],{"class":819},"    socialProviders",[571,1406,847],{"class":766},[571,1408,1409,1412],{"class":573,"line":950},[571,1410,1411],{"class":819},"      google",[571,1413,847],{"class":766},[571,1415,1416,1419,1421,1423,1425,1427],{"class":573,"line":956},[571,1417,1418],{"class":819},"        clientId",[571,1420,535],{"class":766},[571,1422,910],{"class":770},[571,1424,907],{"class":766},[571,1426,538],{"class":770},[571,1428,828],{"class":766},[571,1430,1431,1434,1436,1438,1440,1442],{"class":573,"line":962},[571,1432,1433],{"class":819},"        clientSecret",[571,1435,535],{"class":766},[571,1437,910],{"class":770},[571,1439,907],{"class":766},[571,1441,547],{"class":770},[571,1443,828],{"class":766},[571,1445,1446],{"class":573,"line":968},[571,1447,1448],{"class":766},"      },\n",[571,1450,1451],{"class":573,"line":973},[571,1452,965],{"class":766},[571,1454,1456],{"class":573,"line":1455},21,[571,1457,1458],{"class":766},"  });\n",[571,1460,1462],{"class":573,"line":1461},22,[571,1463,1464],{"class":766},"}\n",[29,1466],{},[32,1468,1470],{"id":1469},"_7-クライアント側の実装","7. クライアント側の実装",[45,1472,1474],{"id":1473},"google-ログインボタン","Google ログインボタン",[57,1476,1480],{"className":1477,"code":1478,"language":1479,"meta":66,"style":66},"language-tsx shiki shiki-themes vitesse-light vitesse-light","// components/GoogleLoginButton.tsx\nimport { authClient } from \"@/lib/auth-client\";\n\nexport function GoogleLoginButton() {\n  const handleGoogleLogin = async () => {\n    await authClient.signIn.social({\n      provider: \"google\",\n      callbackURL: \"/dashboard\", // ログイン後のリダイレクト先\n    });\n  };\n\n  return (\n    \u003Cbutton\n      onClick={handleGoogleLogin}\n      className=\"flex items-center gap-2 px-4 py-2 border rounded-lg hover:bg-gray-50\"\n    >\n      \u003CGoogleIcon />\n      Googleでログイン\n    \u003C/button>\n  );\n}\n\nfunction GoogleIcon() {\n  return (\n    \u003Csvg className=\"w-5 h-5\" viewBox=\"0 0 24 24\">\n      \u003Cpath\n        fill=\"#4285F4\"\n        d=\"M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z\"\n      />\n      \u003Cpath\n        fill=\"#34A853\"\n        d=\"M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z\"\n      />\n      \u003Cpath\n        fill=\"#FBBC05\"\n        d=\"M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z\"\n      />\n      \u003Cpath\n        fill=\"#EA4335\"\n        d=\"M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z\"\n      />\n    \u003C/svg>\n  );\n}\n","tsx",[64,1481,1482,1487,1492,1496,1501,1506,1511,1516,1521,1526,1531,1535,1540,1545,1550,1555,1560,1565,1570,1575,1580,1584,1588,1594,1599,1605,1611,1617,1623,1629,1634,1640,1646,1651,1656,1662,1668,1673,1678,1684,1690,1695,1701,1706],{"__ignoreMap":66},[571,1483,1484],{"class":573,"line":574},[571,1485,1486],{},"// components/GoogleLoginButton.tsx\n",[571,1488,1489],{"class":573,"line":580},[571,1490,1491],{},"import { authClient } from \"@/lib/auth-client\";\n",[571,1493,1494],{"class":573,"line":586},[571,1495,596],{"emptyLinePlaceholder":595},[571,1497,1498],{"class":573,"line":592},[571,1499,1500],{},"export function GoogleLoginButton() {\n",[571,1502,1503],{"class":573,"line":599},[571,1504,1505],{},"  const handleGoogleLogin = async () => {\n",[571,1507,1508],{"class":573,"line":655},[571,1509,1510],{},"    await authClient.signIn.social({\n",[571,1512,1513],{"class":573,"line":841},[571,1514,1515],{},"      provider: \"google\",\n",[571,1517,1518],{"class":573,"line":850},[571,1519,1520],{},"      callbackURL: \"/dashboard\", // ログイン後のリダイレクト先\n",[571,1522,1523],{"class":573,"line":863},[571,1524,1525],{},"    });\n",[571,1527,1528],{"class":573,"line":869},[571,1529,1530],{},"  };\n",[571,1532,1533],{"class":573,"line":874},[571,1534,596],{"emptyLinePlaceholder":595},[571,1536,1537],{"class":573,"line":880},[571,1538,1539],{},"  return (\n",[571,1541,1542],{"class":573,"line":888},[571,1543,1544],{},"    \u003Cbutton\n",[571,1546,1547],{"class":573,"line":896},[571,1548,1549],{},"      onClick={handleGoogleLogin}\n",[571,1551,1552],{"class":573,"line":926},[571,1553,1554],{},"      className=\"flex items-center gap-2 px-4 py-2 border rounded-lg hover:bg-gray-50\"\n",[571,1556,1557],{"class":573,"line":950},[571,1558,1559],{},"    >\n",[571,1561,1562],{"class":573,"line":956},[571,1563,1564],{},"      \u003CGoogleIcon />\n",[571,1566,1567],{"class":573,"line":962},[571,1568,1569],{},"      Googleでログイン\n",[571,1571,1572],{"class":573,"line":968},[571,1573,1574],{},"    \u003C/button>\n",[571,1576,1577],{"class":573,"line":973},[571,1578,1579],{},"  );\n",[571,1581,1582],{"class":573,"line":1455},[571,1583,1464],{},[571,1585,1586],{"class":573,"line":1461},[571,1587,596],{"emptyLinePlaceholder":595},[571,1589,1591],{"class":573,"line":1590},23,[571,1592,1593],{},"function GoogleIcon() {\n",[571,1595,1597],{"class":573,"line":1596},24,[571,1598,1539],{},[571,1600,1602],{"class":573,"line":1601},25,[571,1603,1604],{},"    \u003Csvg className=\"w-5 h-5\" viewBox=\"0 0 24 24\">\n",[571,1606,1608],{"class":573,"line":1607},26,[571,1609,1610],{},"      \u003Cpath\n",[571,1612,1614],{"class":573,"line":1613},27,[571,1615,1616],{},"        fill=\"#4285F4\"\n",[571,1618,1620],{"class":573,"line":1619},28,[571,1621,1622],{},"        d=\"M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z\"\n",[571,1624,1626],{"class":573,"line":1625},29,[571,1627,1628],{},"      />\n",[571,1630,1632],{"class":573,"line":1631},30,[571,1633,1610],{},[571,1635,1637],{"class":573,"line":1636},31,[571,1638,1639],{},"        fill=\"#34A853\"\n",[571,1641,1643],{"class":573,"line":1642},32,[571,1644,1645],{},"        d=\"M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z\"\n",[571,1647,1649],{"class":573,"line":1648},33,[571,1650,1628],{},[571,1652,1654],{"class":573,"line":1653},34,[571,1655,1610],{},[571,1657,1659],{"class":573,"line":1658},35,[571,1660,1661],{},"        fill=\"#FBBC05\"\n",[571,1663,1665],{"class":573,"line":1664},36,[571,1666,1667],{},"        d=\"M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z\"\n",[571,1669,1671],{"class":573,"line":1670},37,[571,1672,1628],{},[571,1674,1676],{"class":573,"line":1675},38,[571,1677,1610],{},[571,1679,1681],{"class":573,"line":1680},39,[571,1682,1683],{},"        fill=\"#EA4335\"\n",[571,1685,1687],{"class":573,"line":1686},40,[571,1688,1689],{},"        d=\"M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z\"\n",[571,1691,1693],{"class":573,"line":1692},41,[571,1694,1628],{},[571,1696,1698],{"class":573,"line":1697},42,[571,1699,1700],{},"    \u003C/svg>\n",[571,1702,1704],{"class":573,"line":1703},43,[571,1705,1579],{},[571,1707,1709],{"class":573,"line":1708},44,[571,1710,1464],{},[45,1712,1713],{"id":1713},"ログインページ全体の例",[57,1715,1717],{"className":1477,"code":1716,"language":1479,"meta":66,"style":66},"// pages/login.tsx\nimport { GoogleLoginButton } from \"@/components/GoogleLoginButton\";\nimport { authClient } from \"@/lib/auth-client\";\nimport { useState } from \"react\";\n\nexport function LoginPage() {\n  const [email, setEmail] = useState(\"\");\n  const [password, setPassword] = useState(\"\");\n  const [error, setError] = useState(\"\");\n\n  const handleEmailLogin = async (e: React.FormEvent) => {\n    e.preventDefault();\n    try {\n      await authClient.signIn.email({ email, password });\n      window.location.href = \"/dashboard\";\n    } catch (err) {\n      setError(\"ログインに失敗しました\");\n    }\n  };\n\n  return (\n    \u003Cdiv className=\"max-w-md mx-auto mt-20 p-6\">\n      \u003Ch1 className=\"text-2xl font-bold mb-6\">ログイン\u003C/h1>\n\n      {/* Google ログイン */}\n      \u003CGoogleLoginButton />\n\n      \u003Cdiv className=\"my-6 flex items-center\">\n        \u003Chr className=\"flex-1\" />\n        \u003Cspan className=\"px-4 text-gray-500\">または\u003C/span>\n        \u003Chr className=\"flex-1\" />\n      \u003C/div>\n\n      {/* メール/パスワード ログイン */}\n      \u003Cform onSubmit={handleEmailLogin} className=\"space-y-4\">\n        {error && \u003Cp className=\"text-red-500\">{error}\u003C/p>}\n        \n        \u003Cinput\n          type=\"email\"\n          placeholder=\"メールアドレス\"\n          value={email}\n          onChange={(e) => setEmail(e.target.value)}\n          className=\"w-full px-4 py-2 border rounded\"\n        />\n        \n        \u003Cinput\n          type=\"password\"\n          placeholder=\"パスワード\"\n          value={password}\n          onChange={(e) => setPassword(e.target.value)}\n          className=\"w-full px-4 py-2 border rounded\"\n        />\n        \n        \u003Cbutton\n          type=\"submit\"\n          className=\"w-full px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600\"\n        >\n          ログイン\n        \u003C/button>\n      \u003C/form>\n    \u003C/div>\n  );\n}\n",[64,1718,1719,1724,1729,1733,1738,1742,1747,1752,1757,1762,1766,1771,1776,1781,1786,1791,1796,1801,1806,1810,1814,1818,1823,1828,1832,1837,1842,1846,1851,1856,1861,1865,1870,1874,1879,1884,1889,1894,1899,1904,1909,1914,1919,1924,1929,1934,1939,1945,1951,1957,1963,1968,1973,1978,1984,1990,1996,2002,2008,2014,2020,2026,2031],{"__ignoreMap":66},[571,1720,1721],{"class":573,"line":574},[571,1722,1723],{},"// pages/login.tsx\n",[571,1725,1726],{"class":573,"line":580},[571,1727,1728],{},"import { GoogleLoginButton } from \"@/components/GoogleLoginButton\";\n",[571,1730,1731],{"class":573,"line":586},[571,1732,1491],{},[571,1734,1735],{"class":573,"line":592},[571,1736,1737],{},"import { useState } from \"react\";\n",[571,1739,1740],{"class":573,"line":599},[571,1741,596],{"emptyLinePlaceholder":595},[571,1743,1744],{"class":573,"line":655},[571,1745,1746],{},"export function LoginPage() {\n",[571,1748,1749],{"class":573,"line":841},[571,1750,1751],{},"  const [email, setEmail] = useState(\"\");\n",[571,1753,1754],{"class":573,"line":850},[571,1755,1756],{},"  const [password, setPassword] = useState(\"\");\n",[571,1758,1759],{"class":573,"line":863},[571,1760,1761],{},"  const [error, setError] = useState(\"\");\n",[571,1763,1764],{"class":573,"line":869},[571,1765,596],{"emptyLinePlaceholder":595},[571,1767,1768],{"class":573,"line":874},[571,1769,1770],{},"  const handleEmailLogin = async (e: React.FormEvent) => {\n",[571,1772,1773],{"class":573,"line":880},[571,1774,1775],{},"    e.preventDefault();\n",[571,1777,1778],{"class":573,"line":888},[571,1779,1780],{},"    try {\n",[571,1782,1783],{"class":573,"line":896},[571,1784,1785],{},"      await authClient.signIn.email({ email, password });\n",[571,1787,1788],{"class":573,"line":926},[571,1789,1790],{},"      window.location.href = \"/dashboard\";\n",[571,1792,1793],{"class":573,"line":950},[571,1794,1795],{},"    } catch (err) {\n",[571,1797,1798],{"class":573,"line":956},[571,1799,1800],{},"      setError(\"ログインに失敗しました\");\n",[571,1802,1803],{"class":573,"line":962},[571,1804,1805],{},"    }\n",[571,1807,1808],{"class":573,"line":968},[571,1809,1530],{},[571,1811,1812],{"class":573,"line":973},[571,1813,596],{"emptyLinePlaceholder":595},[571,1815,1816],{"class":573,"line":1455},[571,1817,1539],{},[571,1819,1820],{"class":573,"line":1461},[571,1821,1822],{},"    \u003Cdiv className=\"max-w-md mx-auto mt-20 p-6\">\n",[571,1824,1825],{"class":573,"line":1590},[571,1826,1827],{},"      \u003Ch1 className=\"text-2xl font-bold mb-6\">ログイン\u003C/h1>\n",[571,1829,1830],{"class":573,"line":1596},[571,1831,596],{"emptyLinePlaceholder":595},[571,1833,1834],{"class":573,"line":1601},[571,1835,1836],{},"      {/* Google ログイン */}\n",[571,1838,1839],{"class":573,"line":1607},[571,1840,1841],{},"      \u003CGoogleLoginButton />\n",[571,1843,1844],{"class":573,"line":1613},[571,1845,596],{"emptyLinePlaceholder":595},[571,1847,1848],{"class":573,"line":1619},[571,1849,1850],{},"      \u003Cdiv className=\"my-6 flex items-center\">\n",[571,1852,1853],{"class":573,"line":1625},[571,1854,1855],{},"        \u003Chr className=\"flex-1\" />\n",[571,1857,1858],{"class":573,"line":1631},[571,1859,1860],{},"        \u003Cspan className=\"px-4 text-gray-500\">または\u003C/span>\n",[571,1862,1863],{"class":573,"line":1636},[571,1864,1855],{},[571,1866,1867],{"class":573,"line":1642},[571,1868,1869],{},"      \u003C/div>\n",[571,1871,1872],{"class":573,"line":1648},[571,1873,596],{"emptyLinePlaceholder":595},[571,1875,1876],{"class":573,"line":1653},[571,1877,1878],{},"      {/* メール/パスワード ログイン */}\n",[571,1880,1881],{"class":573,"line":1658},[571,1882,1883],{},"      \u003Cform onSubmit={handleEmailLogin} className=\"space-y-4\">\n",[571,1885,1886],{"class":573,"line":1664},[571,1887,1888],{},"        {error && \u003Cp className=\"text-red-500\">{error}\u003C/p>}\n",[571,1890,1891],{"class":573,"line":1670},[571,1892,1893],{},"        \n",[571,1895,1896],{"class":573,"line":1675},[571,1897,1898],{},"        \u003Cinput\n",[571,1900,1901],{"class":573,"line":1680},[571,1902,1903],{},"          type=\"email\"\n",[571,1905,1906],{"class":573,"line":1686},[571,1907,1908],{},"          placeholder=\"メールアドレス\"\n",[571,1910,1911],{"class":573,"line":1692},[571,1912,1913],{},"          value={email}\n",[571,1915,1916],{"class":573,"line":1697},[571,1917,1918],{},"          onChange={(e) => setEmail(e.target.value)}\n",[571,1920,1921],{"class":573,"line":1703},[571,1922,1923],{},"          className=\"w-full px-4 py-2 border rounded\"\n",[571,1925,1926],{"class":573,"line":1708},[571,1927,1928],{},"        />\n",[571,1930,1932],{"class":573,"line":1931},45,[571,1933,1893],{},[571,1935,1937],{"class":573,"line":1936},46,[571,1938,1898],{},[571,1940,1942],{"class":573,"line":1941},47,[571,1943,1944],{},"          type=\"password\"\n",[571,1946,1948],{"class":573,"line":1947},48,[571,1949,1950],{},"          placeholder=\"パスワード\"\n",[571,1952,1954],{"class":573,"line":1953},49,[571,1955,1956],{},"          value={password}\n",[571,1958,1960],{"class":573,"line":1959},50,[571,1961,1962],{},"          onChange={(e) => setPassword(e.target.value)}\n",[571,1964,1966],{"class":573,"line":1965},51,[571,1967,1923],{},[571,1969,1971],{"class":573,"line":1970},52,[571,1972,1928],{},[571,1974,1976],{"class":573,"line":1975},53,[571,1977,1893],{},[571,1979,1981],{"class":573,"line":1980},54,[571,1982,1983],{},"        \u003Cbutton\n",[571,1985,1987],{"class":573,"line":1986},55,[571,1988,1989],{},"          type=\"submit\"\n",[571,1991,1993],{"class":573,"line":1992},56,[571,1994,1995],{},"          className=\"w-full px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600\"\n",[571,1997,1999],{"class":573,"line":1998},57,[571,2000,2001],{},"        >\n",[571,2003,2005],{"class":573,"line":2004},58,[571,2006,2007],{},"          ログイン\n",[571,2009,2011],{"class":573,"line":2010},59,[571,2012,2013],{},"        \u003C/button>\n",[571,2015,2017],{"class":573,"line":2016},60,[571,2018,2019],{},"      \u003C/form>\n",[571,2021,2023],{"class":573,"line":2022},61,[571,2024,2025],{},"    \u003C/div>\n",[571,2027,2029],{"class":573,"line":2028},62,[571,2030,1579],{},[571,2032,2034],{"class":573,"line":2033},63,[571,2035,1464],{},[29,2037],{},[32,2039,2041],{"id":2040},"_8-本番公開時の設定","8. 本番公開時の設定",[45,2043,2045],{"id":2044},"oauth-同意画面を本番に変更","OAuth 同意画面を「本番」に変更",[14,2047,2048],{},"開発中は「テスト」モードですが、本番公開時は以下の手順が必要です：",[50,2050,2051,2059,2064],{},[53,2052,2053,167,2056],{},[17,2054,2055],{},"Google Cloud Console",[17,2057,2058],{},"OAuth 同意画面",[53,2060,2061,94],{},[17,2062,2063],{},"「アプリを公開」",[53,2065,2066,2067],{},"Google による審査（通常数日〜数週間）",[342,2068,2069,2072,2075],{},[53,2070,2071],{},"プライバシーポリシーページが必要",[53,2073,2074],{},"利用規約ページが必要",[53,2076,2077],{},"ドメインの所有権確認が必要な場合あり",[45,2079,2081],{"id":2080},"審査を避ける方法小規模サービス向け","審査を避ける方法（小規模サービス向け）",[14,2083,2084],{},"以下の条件を満たす場合、審査なしで公開可能：",[342,2086,2087,2110],{},[53,2088,2089,2092],{},[17,2090,2091],{},"機密性の高いスコープを使用しない",[342,2093,2094,2107],{},[53,2095,2096,2099,2100,2099,2103,2106],{},[64,2097,2098],{},"email",", ",[64,2101,2102],{},"profile",[64,2104,2105],{},"openid"," のみならOK",[53,2108,2109],{},"Gmail API や Drive API などは審査必要",[53,2111,2112],{},[17,2113,2114],{},"ユーザー数が100人未満",[29,2116],{},[32,2118,2120],{"id":2119},"_9-トラブルシューティング","9. トラブルシューティング",[45,2122,2124],{"id":2123},"エラー-redirect_uri_mismatch","エラー: \"redirect_uri_mismatch\"",[14,2126,2127,2130],{},[17,2128,2129],{},"原因",": 設定したリダイレクトURIとアプリからのURIが一致しない",[14,2132,2133,2136],{},[17,2134,2135],{},"解決方法",":",[50,2138,2139,2145,2152,2162],{},[53,2140,2141,2142,2144],{},"Google Cloud Console で ",[17,2143,484],{}," を確認",[53,2146,2147,2148,2151],{},"末尾のスラッシュ ",[64,2149,2150],{},"/"," の有無を確認",[53,2153,2154,2157,2158,2161],{},[64,2155,2156],{},"http"," と ",[64,2159,2160],{},"https"," の違いを確認",[53,2163,2164],{},"ポート番号の確認",[57,2166,2169],{"className":2167,"code":2168,"language":62},[60],"❌ http://localhost:3000/api/auth/callback/google/\n✅ http://localhost:3000/api/auth/callback/google\n",[64,2170,2168],{"__ignoreMap":66},[45,2172,2174],{"id":2173},"エラー-access_denied","エラー: \"access_denied\"",[14,2176,2177,2179],{},[17,2178,2129],{},": テストモード中に未登録ユーザーがアクセス",[14,2181,2182,2136],{},[17,2183,2135],{},[50,2185,2186,2189],{},[53,2187,2188],{},"OAuth 同意画面 → テストユーザーに追加",[53,2190,2191],{},"または「アプリを公開」で本番モードに",[45,2193,2195],{"id":2194},"エラー-invalid_client","エラー: \"invalid_client\"",[14,2197,2198,2200],{},[17,2199,2129],{},": Client ID または Client Secret が間違っている",[14,2202,2203,2136],{},[17,2204,2135],{},[50,2206,2207,2210,2213],{},[53,2208,2209],{},"環境変数が正しく設定されているか確認",[53,2211,2212],{},"コピペ時の余分な空白がないか確認",[53,2214,2215],{},"認証情報を再作成",[45,2217,2218],{"id":2218},"ログインしてもユーザー情報が取得できない",[14,2220,2221,2223],{},[17,2222,2129],{},": スコープが不足している",[14,2225,2226,2136],{},[17,2227,2135],{},[57,2229,2231],{"className":753,"code":2230,"language":755,"meta":66,"style":66},"socialProviders: {\n  google: {\n    clientId: env.GOOGLE_CLIENT_ID,\n    clientSecret: env.GOOGLE_CLIENT_SECRET,\n    scope: [\"email\", \"profile\", \"openid\"], // 明示的に指定\n  },\n},\n",[64,2232,2233,2242,2251,2267,2282,2319,2323],{"__ignoreMap":66},[571,2234,2235,2238,2240],{"class":573,"line":574},[571,2236,2237],{"class":624},"socialProviders",[571,2239,2136],{"class":766},[571,2241,1051],{"class":766},[571,2243,2244,2247,2249],{"class":573,"line":580},[571,2245,2246],{"class":624},"  google",[571,2248,2136],{"class":766},[571,2250,1051],{"class":766},[571,2252,2253,2256,2258,2261,2263,2265],{"class":573,"line":586},[571,2254,2255],{"class":624},"    clientId",[571,2257,2136],{"class":766},[571,2259,2260],{"class":770}," env",[571,2262,907],{"class":766},[571,2264,538],{"class":770},[571,2266,828],{"class":766},[571,2268,2269,2272,2274,2276,2278,2280],{"class":573,"line":592},[571,2270,2271],{"class":624},"    clientSecret",[571,2273,2136],{"class":766},[571,2275,2260],{"class":770},[571,2277,907],{"class":766},[571,2279,547],{"class":770},[571,2281,828],{"class":766},[571,2283,2284,2287,2289,2292,2294,2296,2298,2300,2302,2304,2306,2308,2310,2312,2314,2316],{"class":573,"line":599},[571,2285,2286],{"class":624},"    scope",[571,2288,2136],{"class":766},[571,2290,2291],{"class":766}," [",[571,2293,787],{"class":780},[571,2295,2098],{"class":628},[571,2297,787],{"class":780},[571,2299,1155],{"class":766},[571,2301,781],{"class":780},[571,2303,2102],{"class":628},[571,2305,787],{"class":780},[571,2307,1155],{"class":766},[571,2309,781],{"class":780},[571,2311,2105],{"class":628},[571,2313,787],{"class":780},[571,2315,1165],{"class":766},[571,2317,2318],{"class":618}," // 明示的に指定\n",[571,2320,2321],{"class":573,"line":655},[571,2322,866],{"class":766},[571,2324,2325],{"class":573,"line":841},[571,2326,2327],{"class":766},"},\n",[29,2329],{},[32,2331,2333],{"id":2332},"_10-セキュリティ-チェックリスト","10. セキュリティ チェックリスト",[57,2335,2338],{"className":2336,"code":2337,"language":62},[60],"✅ Client Secret は環境変数で管理（コードに直書きしない）\n✅ Client Secret は暗号化して保存（Cloudflare の Encrypt オプション）\n✅ 本番環境では HTTPS のみを許可\n✅ 不要になった認証情報は削除\n✅ 定期的に認証情報をローテーション\n✅ OAuth 同意画面の情報を最新に保つ\n",[64,2339,2337],{"__ignoreMap":66},[29,2341],{},[32,2343,2344],{"id":2344},"参考リンク",[99,2346,2347,2357],{},[102,2348,2349],{},[105,2350,2351,2354],{},[108,2352,2353],{},"リソース",[108,2355,2356],{},"URL",[115,2358,2359,2369,2380,2391],{},[105,2360,2361,2363],{},[120,2362,2055],{},[120,2364,2365],{},[674,2366,2367],{"href":2367,"rel":2368},"https://console.cloud.google.com/",[678],[105,2370,2371,2374],{},[120,2372,2373],{},"OAuth 2.0 ドキュメント",[120,2375,2376],{},[674,2377,2378],{"href":2378,"rel":2379},"https://developers.google.com/identity/protocols/oauth2",[678],[105,2381,2382,2385],{},[120,2383,2384],{},"Better Auth - Google Provider",[120,2386,2387],{},[674,2388,2389],{"href":2389,"rel":2390},"https://www.better-auth.com/docs/authentication/social-providers",[678],[105,2392,2393,2396],{},[120,2394,2395],{},"Cloudflare Workers Secrets",[120,2397,2398],{},[674,2399,2400],{"href":2400,"rel":2401},"https://developers.cloudflare.com/workers/configuration/secrets/",[678],[29,2403],{},[14,2405,2406],{},[2407,2408,2409],"em",{},"このドキュメントは Chat Story サービスの Google OAuth 設定ガイドとして作成されました。",[2411,2412,2413],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sxvE3, html code.shiki .sxvE3{--shiki-default:#A0ADA0;--shiki-dark:#A0ADA0}html pre.shiki code .senZ8, html code.shiki .senZ8{--shiki-default:#59873A;--shiki-dark:#59873A}html pre.shiki code .sdGka, html code.shiki .sdGka{--shiki-default:#B56959;--shiki-dark:#B56959}html pre.shiki code .sHkkW, html code.shiki .sHkkW{--shiki-default:#1E754F;--shiki-dark:#1E754F}html pre.shiki code .shFtX, html code.shiki .shFtX{--shiki-default:#999999;--shiki-dark:#999999}html pre.shiki code .s4oTP, html code.shiki .s4oTP{--shiki-default:#B07D48;--shiki-dark:#B07D48}html pre.shiki code .sMJiu, html code.shiki .sMJiu{--shiki-default:#B5695977;--shiki-dark:#B5695977}html pre.shiki code .stQ0i, html code.shiki .stQ0i{--shiki-default:#AB5959;--shiki-dark:#AB5959}html pre.shiki code .sz8Xr, html code.shiki .sz8Xr{--shiki-default:#998418;--shiki-dark:#998418}html pre.shiki code .sSkh3, html code.shiki .sSkh3{--shiki-default:#2E8F82;--shiki-dark:#2E8F82}",{"title":66,"searchDepth":580,"depth":580,"links":2415},[2416,2417,2420,2423,2428,2432,2435,2439,2443,2447,2453,2454],{"id":34,"depth":580,"text":34},{"id":42,"depth":580,"text":43,"children":2418},[2419],{"id":47,"depth":586,"text":48},{"id":74,"depth":580,"text":75,"children":2421},[2422],{"id":78,"depth":586,"text":79},{"id":148,"depth":580,"text":149,"children":2424},[2425,2426,2427],{"id":152,"depth":586,"text":153},{"id":354,"depth":586,"text":355},{"id":383,"depth":586,"text":384},{"id":420,"depth":580,"text":421,"children":2429},[2430,2431],{"id":424,"depth":586,"text":425},{"id":512,"depth":586,"text":513},{"id":552,"depth":580,"text":553,"children":2433},[2434],{"id":556,"depth":586,"text":557},{"id":745,"depth":580,"text":746,"children":2436},[2437,2438],{"id":749,"depth":586,"text":750},{"id":979,"depth":586,"text":980},{"id":1469,"depth":580,"text":1470,"children":2440},[2441,2442],{"id":1473,"depth":586,"text":1474},{"id":1713,"depth":586,"text":1713},{"id":2040,"depth":580,"text":2041,"children":2444},[2445,2446],{"id":2044,"depth":586,"text":2045},{"id":2080,"depth":586,"text":2081},{"id":2119,"depth":580,"text":2120,"children":2448},[2449,2450,2451,2452],{"id":2123,"depth":586,"text":2124},{"id":2173,"depth":586,"text":2174},{"id":2194,"depth":586,"text":2195},{"id":2218,"depth":586,"text":2218},{"id":2332,"depth":580,"text":2333},{"id":2344,"depth":580,"text":2344},null,"Google Cloud ConsoleでOAuth認証情報を取得し、Better Authと連携する手順を解説","md",{},"/google-oauth-setup-guide",false,"2025-12-11T00:00:00.000Z",{"title":5,"description":2456},"2025-12/2025-12-11/google-oauth-setup-guide",[2465,2466,2467,2468],"Google OAuth","Better Auth","Cloudflare Workers","認証","TLCwSoh-X7ohcz5wvvU-mItMffUc9546ZogSBX3x5oU",[],[2472,2475,2479,2482,2486],{"title":2473,"path":2474,"publishedAt":2461},"Chat Story 実装ガイド","/chat-story-implementation-guide",{"title":2476,"path":2477,"publishedAt":2478},"2026年7月30日の開発日記 - 3つのリポジトリに同じ問いを投げた朝","/2026-07-30-diary","2026-07-30T00:00:00.000Z",{"title":2480,"path":2481,"publishedAt":2478},"Cloudflare Worker のバンドル削減2日目、外部HTML化で287KiB空けて miller-viewer 島は予測の1割だった","/nuxt-worker-bundle-reduction-miller-viewer",{"title":2483,"path":2484,"publishedAt":2485},"2026年7月29日の開発日記 - 朝いちで ~/.claude が消えた日に、7本の作業が並走した","/2026-07-29-diary","2026-07-29T00:00:00.000Z",{"title":2487,"path":2488,"publishedAt":2485},"Vueページは必ずWorkerバンドルに載る — 静的HTML化と「島マウント」でCloudflare Workersの上限から逃げる","/worker-bundle-reduction-content-islands","https://log.eurekapu.com/og/blog/google-oauth-setup-guide.png?v=2025-12-11T00%3A00%3A00.000Z&title=Google%20OAuth%20%E8%A8%AD%E5%AE%9A%E3%82%AC%E3%82%A4%E3%83%89&author=Kei%20Komatsu&sig=6509b5e13da9b4dd",1785654676327]