メインコンテンツへスキップ
記事一覧に戻る
programmingadalab focus 開発記 (3/5)

サーバーレスで Google ログインを実装する — Cloudflare Pages Functions + PKCE

常駐サーバーなしで Google OAuth 2.0 ログインを実装する方法を解説。Authorization Code Flow + PKCE の仕組み、Cloudflare Pages Functions でのトークン交換、自前 JWT によるセッション管理まで、adalab focus の実装をベースに紹介します。

2026-06-147 min readAdabana Saki
-
OAuthPKCEGoogle ログインCloudflare PagesJWT認証サーバーレスadalab focus
シリーズ中級者〜上級者

adalab focus 開発記

学習管理 PWA「adalab focus」の開発で得た知見を解説。ローカルファースト設計、オフライン同期、サーバーレス認証、タイマーの状態設計、ブラウザ拡張との連携まで

進捗3 / 5

サーバーレスで Google ログインを実装する — Cloudflare Pages Functions + PKCE

adalab focus 開発記の第 3 回です。今回は認証の話。「Google でログイン」を、**常駐サーバーなし(Cloudflare Pages Functions のみ)**で実装します。

Firebase Auth や Auth0 を使えば一瞬では?と思うかもしれません。実際それも正解です。ただ、OAuth は一度自分の手で通しておくと外部サービスのドキュメントの解像度が段違いに上がるので、個人開発こそ自前実装の価値があると思っています。

全体フロー

使うのは Authorization Code Flow + PKCE です。SPA でも安全にコード交換できるのがポイントです。

Text

PKCE(Proof Key for Code Exchange)の役割は ①〜⑤ です。「認可コードを盗まれても、code_verifier を知らなければトークンに交換できない」という仕掛けで、リダイレクト経由でコードが漏れるリスクを潰します。

① PKCE の準備はブラウザだけで完結する

code_verifier はランダム文字列、code_challenge はその SHA-256 ハッシュです。Web Crypto API だけで作れます:

TypeScript

verifier は sessionStorage に置き、challenge だけを認可 URL に乗せて Google へ飛ばします。

TypeScript

⑤ トークン交換は Functions でやる(ここだけは譲れない)

トークン交換には client_secret が必要です。これをブラウザに置いた瞬間に「secret」ではなくなるので、この 1 ステップのためだけにサーバーサイドが要ります。Cloudflare Pages Functions なら functions/api/auth/callback.ts を置くだけです:

TypeScript

シークレットは wrangler の環境変数(ローカルは .dev.vars、本番はダッシュボード)に置きます。.dev.vars は必ず .gitignore に入れてください。これを公開リポジトリに push する事故は本当によく見ます。

⑦ セッションは自前 JWT で

Google の id_token をそのままセッションに使うこともできますが、有効期限が 1 時間しかなく、リフレッシュ管理が面倒です。adalab focus ではログイン成立時に自前の JWT を発行して、以降の API はそれだけで認証しています。

TypeScript

検証側も同じく Web Crypto だけで書けます。Workers ランタイムは Node ではないので「とりあえず jsonwebtoken」が使えない場面があるのですが、HS256 程度なら標準 API で十分でした。

Text

ハマりどころメモ

実装中に踏んだものを正直に書いておきます:

  • redirect_uri の完全一致。Google Cloud Console の設定と 1 文字でも違うと redirect_uri_mismatch。http://localhost:5173 と http://127.0.0.1:5173 は別物です
  • 時計ずれで JWT が「未来」になる。exp 検証に数十秒のマージン(leeway)を入れないと、端末の時計が少し進んでいるユーザーだけログインできなくなります
  • 401 時の UX。API クライアント側で 401 を一元処理してログイン画面へ誘導しないと、画面ごとに半端な壊れ方をします

まとめ

  • SPA の Google ログインは Authorization Code Flow + PKCE が現在の正解
  • ブラウザでやれるのは PKCE 生成まで。トークン交換だけはサーバー(Functions)が必須
  • セッションは自前 JWT にすると Google への依存がログインの瞬間だけになる
  • Workers ランタイムでは Web Crypto API が標準。HS256 の署名/検証はライブラリなしで書ける

次回は一番面白かった部分、ポモドーロタイマーの状態設計です。「タイマーは setInterval で作ってはいけない」という話をします。

リンク