フロントエンドからのOAuthフロー
SPAでPKCEを用いたAuthorization Codeフローを実装し、コードをトークンと交換してアクセストークンを安全に保存し、Implicitフローを避けます。
「フロントエンドからのOAuthフロー」はCoddyKit上の無料Frontend Academyレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはFrontend Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Frontend Academyコースには全4レッスンが含まれています。
OAuthとは
OAuth 2.0は委任プロトコルです。ユーザーのパスワードを一度も見ることなく、アプリがユーザーに代わって第三者サービス(Google、GitHubなど)を利用する許可を取得します。「Googleでログイン」、GitHub OAuthアプリ、その他多くの最新の認証方式で使用されています。
主な役割
リソースオーナー:ユーザー。クライアント:あなたのアプリ。認可サーバー:OAuthプロバイダー(Google、Auth0)。リソースサーバー:アクセストークンによって保護されるAPI。
Authorization Codeフロー
サーバーサイドアプリ向けの標準的で安全なフローです。1)ユーザーをプロバイダーのログイン画面にリダイレクトします。2)ユーザーがログインして同意します。3)プロバイダーが認可コードを付けてリダイレクトします。4)サーバーがコードをアクセストークンと交換します(サーバーだけが保持するシークレットです)。
SPAでPKCEを使う理由
SPAはクライアントシークレットを安全に保持できません(ブラウザのバンドルに含まれてしまうためです)。PKCE(Proof Key for Code Exchange)は、シークレットをリクエストごとのcode verifier/challengeに置き換えます。現在はすべてのOAuthパブリッククライアントで標準となっています。
PKCEフローの手順
1)ランダムなcode_verifierを生成します。2)SHA-256でハッシュ化し、code_challengeを作ります。3)challengeを付けて/authorizeにリダイレクトします。4)同意後、codeを受け取ります。5)code + verifierをアクセストークンと交換します。プロバイダーはchallenge = hash(verifier)であることを検証します。
Code VerifierとChallengeの生成
verifierはランダムな文字列で、challengeはそのSHA-256をBase64 URLエンコードしたものです。
function base64url(arr) {
return btoa(String.fromCharCode(...arr))
.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
}
async function generatePKCE() {
const arr = new Uint8Array(32);
crypto.getRandomValues(arr);
const verifier = base64url(arr);
const hash = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(verifier));
const challenge = base64url(new Uint8Array(hash));
return { verifier, challenge };
}プロバイダーへのリダイレクト
challenge、state(CSRF対策)、scopesを含むauthorize URLを組み立てます。
const { verifier, challenge } = await generatePKCE();
const state = crypto.randomUUID();
sessionStorage.setItem('pkce_verifier', verifier);
sessionStorage.setItem('oauth_state', state);
const url = new URL('https://accounts.google.com/o/oauth2/v2/auth');
url.searchParams.set('client_id', CLIENT_ID);
url.searchParams.set('redirect_uri', `${origin}/auth/callback`);
url.searchParams.set('response_type', 'code');
url.searchParams.set('scope', 'openid email profile');
url.searchParams.set('code_challenge', challenge);
url.searchParams.set('code_challenge_method', 'S256');
url.searchParams.set('state', state);
window.location.href = url.toString();コールバックの処理
プロバイダーは?code=...&state=...を付けてコールバックURLにリダイレクトします。CSRFを防ぐためにstateを検証してから、codeを交換します。
// /auth/callback page:
const params = new URLSearchParams(window.location.search);
const code = params.get('code');
const returnedState = params.get('state');
const expected = sessionStorage.getItem('oauth_state');
if (returnedState !== expected) throw new Error('Bad state');
const verifier = sessionStorage.getItem('pkce_verifier');
const tokens = await fetch('https://oauth2.googleapis.com/token', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'authorization_code',
code,
client_id: CLIENT_ID,
redirect_uri: `${origin}/auth/callback`,
code_verifier: verifier
})
}).then(r => r.json());
// tokens: { access_token, id_token, refresh_token, expires_in }トークンを安全に保存する
ベストプラクティスは、アクセストークンをlocalStorageに保存しないことです(XSSで盗まれる可能性があります)。選択肢は次の2つです。1)メモリ内だけに保存する(更新時に消去されるため、再認証が必要です)。2)HttpOnly Cookieを使用する(PKCEフロー後にバックエンドが設定するため、JavaScriptからは盗めません)。
Implicitフローを避ける
古いImplicitフローは、URLフラグメントにアクセストークンを直接返します。OAuth 2.0 Security BCPでは非推奨となっており、ブラウザ履歴やリファラーにトークンが漏れるためです。常にAuthorization Code + PKCEを使用します。
リフレッシュトークン
アクセストークンの有効期限は通常1時間です。より長く有効なリフレッシュトークンを使うと、新しいアクセストークンをユーザーに気付かれずに取得できます。SPAでは、リフレッシュトークンをHttpOnly Cookie経由で提供する方式が増えています。localStorageは決して使用しません。
IDトークンとアクセストークン
IDトークン(OpenID Connect):ユーザーが誰であるかを証明するJWT。アクセストークン:APIの呼び出しに使用する不透明トークンまたはJWT。信頼する前に、IDトークンの署名とクレーム(iss、aud、exp、nonce)を検証します。
認証ライブラリ
自作しないでください。生のOIDCにはoidc-client-ts、Auth0にはauth0/spa-js、Clerkには@clerk/clerk-react、NextにはNextAuth.js/Auth.js、NuxtにはNuxt-authを使用します。これらがPKCE、リフレッシュ、ストレージを処理します。
確認問題
Single-Page Applicationは、基本的なAuthorization Codeフローだけでなく、なぜAuthorization CodeフローとPKCE(Proof Key for Code Exchange)を組み合わせる必要があるのでしょうか。
まとめ:フロントエンドのOAuth
Authorization Code + PKCEはSPAにおける最新の標準です。リクエストごとにverifierとS256 challengeを生成します。challenge + stateを付けて/authorizeにリダイレクトします。コールバックでstateを検証します。code + verifierをトークンと交換します。Implicitフローは決して使用しません。トークンの保存にはHttpOnly Cookieを優先します。ライブラリ(auth0-spa-js、oidc-client-ts、NextAuth)を使用し、自作しないでください。
よくある質問
「フロントエンドからのOAuthフロー」レッスンは無料ですか?
はい。「フロントエンドからのOAuthフロー」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Frontend Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Frontend Academyコースには全4レッスンが含まれています。
「フロントエンドからのOAuthフロー」で何を学びますか?
SPAでPKCEを用いたAuthorization Codeフローを実装し、コードをトークンと交換してアクセストークンを安全に保存し、Implicitフローを避けます。 ブラウザで直接実行するハンズオンコードでFrontend Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Frontend Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのFrontend Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。
「フロントエンドからのOAuthフロー」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このFrontend Academyレッスンでコードを書いて実行できますか?
はい。すべてのFrontend Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。