OAuth 2.0の2つのグラントタイプを徹底解説:Authorization Code GrantとClient Credentials Grantの違いと使い分け

知識

OAuth 2.0はWebサービスやAPIへのアクセス権限を安全に委譲するための業界標準プロトコルです。RFC 6749で定義されており、複数の「グラントタイプ(認可付与方式)」が用意されています。その中でも実務で最もよく使われるのが、Authorization Code Grant(認可コードグラント)Client Credentials Grant(クライアント資格情報グラント)の2つです。

この記事では、それぞれのフローの仕組みをシーケンス図で視覚的に解説し、実際のユースケースや選び方の基準を分かりやすく説明します。OAuth 2.0を学び始めたエンジニアや、認証・認可の設計を担当するバックエンドエンジニアの方に特に役立つ内容です。


OAuth 2.0 とグラントタイプとは

OAuth 2.0は「認可(Authorization)」のフレームワークです。ユーザーや別のサービスが、リソースサーバー上の保護されたデータへアクセスするための「アクセストークン」を安全に取得する仕組みを標準化しています。

グラントタイプとは、アクセストークンをどのような方法で取得するかを定めた方式のことです。RFC 6749では以下の4種類が定義されています。

グラントタイプ主な用途ユーザー関与
Authorization Code GrantWebアプリ・モバイルアプリあり
Client Credentials Grantサーバー間通信(M2M)なし
Implicit GrantSPAなど(現在は非推奨)あり
Resource Owner Password Credentials高信頼クライアント(非推奨)あり

Implicit GrantとResource Owner Password Credentialsは現在セキュリティ上の理由から非推奨とされており、新規の実装では使用しないことが強く推奨されています。現代の実装ではAuthorization Code Grant(PKCEと併用)またはClient Credentials Grantが主流です。


Authorization Code Grant とは

Authorization Code Grant(認可コードグラント)は、OAuth 2.0の中で最も広く使われるグラントタイプです。「Googleアカウントでログイン」「Twitterでログイン」のようなソーシャルログイン機能がこの方式を採用しています。

このフローの最大の特徴は、アクセストークンを直接発行するのではなく、一時的な「認可コード(code)」を経由する2段階の仕組みを採用していることです。これにより、アクセストークンがブラウザのURLやログに露出するリスクを大幅に低減しています。


Authorization Code Grant の処理フロー

OAuth 2.0 Authorization Code Grant フロー図 - ユーザー・クライアント・認可サーバー・リソースサーバーの4者間シーケンス

フローは以下の10ステップで構成されます。

  1. ログインリクエスト: ユーザーがクライアント(Webアプリ)上の「ログイン」ボタンをクリックする
  2. 認可リクエスト: クライアントがユーザーを認可サーバーのエンドポイントにリダイレクトする(client_id・scope・redirect_uriを含む)
  3. ログイン・同意画面の表示: 認可サーバーがユーザーにログインフォームとアクセス許可の同意画面を表示する
  4. 認証情報入力・アクセス同意: ユーザーが認証情報を入力し、アクセスに同意する
  5. 認可コード発行: 認可サーバーが短命の認可コード(code)をクライアントのredirect_uriに送信する
  6. トークンリクエスト: クライアントが認可コードをトークンエンドポイントに送信する(client_secret も含む)
  7. アクセストークン発行: 認可サーバーがアクセストークン(およびリフレッシュトークン)を発行する
  8. APIリクエスト: クライアントがアクセストークンをBearerトークンとしてリソースサーバーに送信する
  9. 保護リソースの返却: リソースサーバーがトークンを検証し、要求されたデータを返す
  10. 結果表示: クライアントがユーザーに結果を表示する

ステップ5の「認可コード」は非常に短命(通常10分以内)であり、1度しか使用できません。これがセキュリティの核心部分です。実際のアクセストークンはステップ6のバックエンド間の通信(backchannel)でのみやり取りされるため、ブラウザのアドレスバーやログにトークンが露出しません。


PKCE(Proof Key for Code Exchange)との組み合わせ

モバイルアプリやSPA(シングルページアプリケーション)では、client_secretをクライアント側に安全に保管できないという問題があります。そのため、現代ではPKCE(ピクシー)と呼ばれる拡張仕様と組み合わせることが強く推奨されています。

PKCEのフローは以下の通りです。

  1. クライアントがランダムな文字列 code_verifier を生成する
  2. code_verifier をSHA-256でハッシュ化して code_challenge を作成する
  3. 認可リクエスト時に code_challengecode_challenge_method=S256 を送信する
  4. トークンリクエスト時に code_verifier(元の値)を送信する
  5. 認可サーバーがハッシュ値を検証してトークンを発行する
# code_verifier の生成例(シェルスクリプト)
code_verifier=UEPrpK2MDu5bSJ6Pahy4ANgoey1avN5IQmDtb5A

# code_challenge の生成 (S256メソッド)
code_challenge=Eq4yyx7ALQHto1gbEnwf7jsNxTVy7WuvI5choD2C4SY

echo "code_verifier: $code_verifier"
echo "code_challenge: $code_challenge"


Client Credentials Grant とは

Client Credentials Grant(クライアント資格情報グラント)は、ユーザーが一切関与しない、サービス同士の通信(Machine-to-Machine, M2M)を想定したグラントタイプです。

マイクロサービスアーキテクチャでは、複数のサービスが互いにAPIを呼び出すことが頻繁に発生します。このとき、呼び出し元サービスが「自分自身の身分証明」として client_id と client_secret を認可サーバーに提示し、アクセストークンを取得します。ユーザーへのリダイレクトや同意画面は一切不要です。


Client Credentials Grant の処理フロー

OAuth 2.0 Client Credentials Grant フロー図 - クライアント・認可サーバー・リソースサーバーの3者間シーケンス

フローはシンプルな5ステップです。

  1. トークンリクエスト: クライアントが client_id と client_secret を認可サーバーのトークンエンドポイントに送信する
  2. 認証確認: 認可サーバーがクライアントの認証情報を検証する
  3. アクセストークン発行: 認証成功後、認可サーバーがアクセストークンを発行する(リフレッシュトークンは通常発行されない)
  4. APIリクエスト: クライアントがアクセストークンをBearerトークンとしてリソースサーバーに送信する
  5. 保護リソースの返却: リソースサーバーがトークンを検証し、データを返す

実際のトークンリクエストのHTTPリクエストは以下のようになります。

# Client Credentials Grant のトークンリクエスト例
curl -X POST https://auth-server.example.com/token   -H "Content-Type: application/x-www-form-urlencoded"   -d "grant_type=client_credentials"   -d "client_id=my-service-client"   -d "client_secret=my-secret-key"   -d "scope=api.read api.write"

# レスポンス例
# {
#   "access_token": "eyJhbGciOiJSUzI1NiIsInR...",
#   "token_type": "Bearer",
#   "expires_in": 3600,
#   "scope": "api.read api.write"
# }

Client Credentials Grantではリフレッシュトークンが発行されないため、アクセストークンの有効期限が切れた場合は再度トークンリクエストを送信する必要があります。実装では、トークンの有効期限を管理してキャッシュする仕組みを設けることが推奨されます。


二つのグラントタイプの使い分け

OAuth 2.0 Authorization Code Grant と Client Credentials Grant の比較図

最も重要な選択基準は「ユーザー(人間)が関与するか否か」です。

観点Authorization Code GrantClient Credentials Grant
ユーザーの関与必要(認証・同意)不要
関与する主体ユーザー / クライアント / 認可サーバークライアント / 認可サーバー
認証情報ユーザーのID・パスワードclient_id + client_secret
フローの複雑さ複雑(リダイレクト・コード交換)シンプル(1リクエスト)
リフレッシュトークンあり通常なし
セキュリティ推奨PKCE 併用が必須client_secret の厳重管理が必須
代表的なユースケースSNSログイン / Webアプリ認証マイクロサービス間通信 / バッチ処理


Authorization Code Grant を選ぶべきケース

以下のシナリオでは Authorization Code Grant(PKCEと組み合わせて)を選択します。

  • 「Googleアカウントでログイン」「GitHubでログイン」などのソーシャルログイン機能を実装する場合
  • ユーザーの許可を得てサードパーティAPIにアクセスする場合(例: ユーザーのカレンダーデータを取得する)
  • Webアプリケーション・モバイルアプリ・SPAでユーザー認証を行う場合
  • ユーザーごとに異なるスコープ(権限)を付与する必要がある場合


Client Credentials Grant を選ぶべきケース

以下のシナリオでは Client Credentials Grant を選択します。

  • マイクロサービスアーキテクチャにおけるサービス間API呼び出し(例: 注文サービスが在庫サービスのAPIを呼ぶ)
  • 夜間バッチ処理・定期タスクでAPIを叩く場合
  • CI/CDパイプラインからAPIにアクセスする場合
  • IoTデバイスがバックエンドAPIにデータを送信する場合
  • ユーザーの代理ではなく、サービス自身のリソースにアクセスする場合


実装上の注意点とセキュリティ

どちらのグラントタイプを使用する場合も、以下のセキュリティ上の考慮が必要です。

  • HTTPS の使用: すべての通信はHTTPS(TLS)上で行うこと。HTTP上でのOAuthは意味をなしません
  • トークンの保管: アクセストークンをLocalStorageに保存するのは危険です。メモリまたはHttpOnly Cookieを使用してください
  • client_secret の管理: Client Credentials Grantのclient_secretはソースコードにハードコーディングせず、環境変数やシークレット管理サービス(AWS Secrets Manager等)で管理する
  • スコープの最小化: 必要最小限のスコープ(権限)のみを要求する(最小権限の原則)
  • トークンの有効期限: アクセストークンの有効期限は短く設定し、必要に応じてリフレッシュトークンで更新する
# Python での Client Credentials Grant 実装例(requests ライブラリ使用)
import os
import requests
import time

class OAuth2ClientCredentials:
    def __init__(self, token_url, client_id, client_secret, scope):
        self.token_url = token_url
        self.client_id = client_id
        self.client_secret = client_secret
        self.scope = scope
        self._token = None
        self._expires_at = 0

    def get_token(self):
        # 有効期限の60秒前に再取得(バッファを設ける)
        if self._token and time.time() < self._expires_at - 60:
            return self._token

        response = requests.post(
            self.token_url,
            data={
                "grant_type": "client_credentials",
                "client_id": self.client_id,
                "client_secret": self.client_secret,
                "scope": self.scope,
            }
        )
        response.raise_for_status()
        token_data = response.json()

        self._token = token_data["access_token"]
        self._expires_at = time.time() + token_data.get("expires_in", 3600)
        return self._token

# 使用例(環境変数からclient_secretを取得)
client = OAuth2ClientCredentials(
    token_url="https://auth-server.example.com/token",
    client_id=os.environ["CLIENT_ID"],
    client_secret=os.environ["CLIENT_SECRET"],
    scope="api.read"
)

token = client.get_token()
headers = {"Authorization": f"Bearer {token}"}
response = requests.get("https://api.example.com/data", headers=headers)


まとめ

Authorization Code GrantとClient Credentials Grantは、OAuth 2.0の中で現代のシステム設計において最も重要な2つのグラントタイプです。それぞれの特性を正しく理解し、シナリオに応じて適切に使い分けることが、安全なシステム設計の基本となります。

  • Authorization Code Grant: ユーザーが関与するWebアプリ・モバイルアプリの認証に使用。PKCEと組み合わせることでさらに安全になる
  • Client Credentials Grant: ユーザーが関与しないサーバー間通信(M2M)に使用。シンプルなフローで実装しやすい

実際の開発では、Auth0・Keycloak・AWS Cognitoなどの認証プラットフォームを活用することで、これらのフローを自前で実装することなく安全に利用できます。まずは今回解説したフローの全体像を把握した上で、各プラットフォームのドキュメントを読み進めていくと理解が深まります。


参考リソース

コメント

タイトルとURLをコピーしました