サーバーレスで Google ログインを実装する — Cloudflare Pages Functions + PKCE
常駐サーバーなしで Google OAuth 2.0 ログインを実装する方法を解説。Authorization Code Flow + PKCE の仕組み、Cloudflare Pages Functions でのトークン交換、自前 JWT によるセッション管理まで、adalab focus の実装をベースに紹介します。
adalab focus 開発記
学習管理 PWA「adalab focus」の開発で得た知見を解説。ローカルファースト設計、オフライン同期、サーバーレス認証、タイマーの状態設計、ブラウザ拡張との連携まで
サーバーレスで Google ログインを実装する — Cloudflare Pages Functions + PKCE
adalab focus 開発記の第 3 回です。今回は認証の話。「Google でログイン」を、**常駐サーバーなし(Cloudflare Pages Functions のみ)**で実装します。
Firebase Auth や Auth0 を使えば一瞬では?と思うかもしれません。実際それも正解です。ただ、OAuth は一度自分の手で通しておくと外部サービスのドキュメントの解像度が段違いに上がるので、個人開発こそ自前実装の価値があると思っています。
全体フロー
使うのは Authorization Code Flow + PKCE です。SPA でも安全にコード交換できるのがポイントです。
PKCE(Proof Key for Code Exchange)の役割は ①〜⑤ です。「認可コードを盗まれても、code_verifier を知らなければトークンに交換できない」という仕掛けで、リダイレクト経由でコードが漏れるリスクを潰します。
① PKCE の準備はブラウザだけで完結する
code_verifier はランダム文字列、code_challenge はその SHA-256 ハッシュです。Web Crypto API だけで作れます:
verifier は sessionStorage に置き、challenge だけを認可 URL に乗せて Google へ飛ばします。
⑤ トークン交換は Functions でやる(ここだけは譲れない)
トークン交換には client_secret が必要です。これをブラウザに置いた瞬間に「secret」ではなくなるので、この 1 ステップのためだけにサーバーサイドが要ります。Cloudflare Pages Functions なら functions/api/auth/callback.ts を置くだけです:
シークレットは wrangler の環境変数(ローカルは .dev.vars、本番はダッシュボード)に置きます。.dev.vars は必ず .gitignore に入れてください。これを公開リポジトリに push する事故は本当によく見ます。
⑦ セッションは自前 JWT で
Google の id_token をそのままセッションに使うこともできますが、有効期限が 1 時間しかなく、リフレッシュ管理が面倒です。adalab focus ではログイン成立時に自前の JWT を発行して、以降の API はそれだけで認証しています。
検証側も同じく Web Crypto だけで書けます。Workers ランタイムは Node ではないので「とりあえず jsonwebtoken」が使えない場面があるのですが、HS256 程度なら標準 API で十分でした。
ハマりどころメモ
実装中に踏んだものを正直に書いておきます:
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 で作ってはいけない」という話をします。