0Pricing
Frontend Academy · レッスン

フロントエンドからの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フィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. XSS対策:出力エンコーディングとCSP
  2. CSRF:SameSite Cookieとトークン
  3. Content Security Policy:nonceとhash
  4. フロントエンドからのOAuthフロー
← Frontend Academyに戻る