サービス間委任 (Service-to-service delegation)
一部の API アーキテクチャでは、バックエンドサービスがサインイン済みユーザーからリクエストを受け取り、そのユーザーのアイデンティティを保持したまま別のバックエンドサービスを呼び出す必要があります。
例えば:
ユーザー -> API A -> API B
API B は次の 2 点を知る必要があります:
- 呼び出し元が信頼できるサービス(例:API A)であること。
- 操作が元のユーザーのために実行されていること。
Logto のトークンエクスチェンジグラントを利用して、ユーザーのアクセス トークン (Access token) を下流の API リソースをオーディエンス (Audience) とする新しいアクセス トークン (Access token) に交換します。これは OAuth 2.0 のトークンエクスチェンジパターンに従い、元のユーザートークンを下流サービスに転送することを回避します。
このフローを使うべき場合
サービス間委任を利用するのは、次のような場合です:
- API A が Logto のトークンエンドポイントに安全に認証できるバックエンドサービスである。
- API A が Logto 発行のユーザーアクセス トークン (Access token) を受け取る。
- API A が同じユーザーの代理で API B を呼び出す必要がある。
- API B が自分の API リソースをオーディエンス (Audience) とする 1 つのアクセス トークン (Access token) を検証すべきである。
ユーザーがいない純粋なマシン間通信の場合はこのフローを使用しないでください。その場合は クライアントクレデンシャルフロー を利用してください。サポートや管理者、エージェントなど、あるユーザーが一時的に別のユーザーとして行動する場合は、ユーザーなりすまし (User impersonation) を利用してください。
仕組み
交換されたアクセス トークン (Access token) は元のユーザー(sub)を表し、下流の API リソース(aud)にバインドされます。下流の API は client_id クレーム (Claim) を確認することで、交換を開始したアプリケーションを特定できます。
前提条件
- 関連するサービス用の API リソースを作成します。詳しくは グローバル API リソースの保護 を参照してください。
- API B の権限 (Permissions) を設定し、ロール (Role) または組織ロール (Organization role) を通じてユーザーに割り当てます。
- API A には、アプリシークレットで安全に認証できるサーバーサイドアプリ(マシン間通信アプリや従来型 Web アプリなど)を使用します。
- API A のアプリケーションでトークンエクスチェンジを有効にします。
トークンエクスチェンジグラントを使用する前に、アプリケーションで有効化する必要があります:
- コンソール > アプリケーション に移動し、対象のアプリケーションを選択します。
- アプリケーション設定で「トークンエクスチェンジ」セクションを探します。
- 「トークンエクスチェンジを許可する」トグルを有効にします。
セキュリティ上の理由から、トークンエクスチェンジはデフォルトで無効になっています。有効化しない場合、「このアプリケーションではトークンエクスチェンジは許可されていません」というエラーが返されます。
下流 API 用のアクセス トークン (Access token) をリクエストする
API A が API B を呼び出す必要がある場合、Logto の トークンエンドポイント にトークンエクスチェンジリクエストを送信します。
従来型 Web アプリやアプリシークレットを持つマシン間通信アプリの場合、Authorization ヘッダーに認証情報を含めます:
POST /oidc/token HTTP/1.1
Host: tenant.logto.app
Content-Type: application/x-www-form-urlencoded
Authorization: Basic <base64(api-a-app-id:api-a-app-secret)>
grant_type=urn:ietf:params:oauth:grant-type:token-exchange
&subject_token=<user_access_token_received_by_api_a>
&subject_token_type=urn:ietf:params:oauth:token-type:access_token
&resource=https://api-b.example.com
&scope=read:orders
パラメーター:
grant_type:urn:ietf:params:oauth:grant-type:token-exchangeを指定します。subject_token:API A が受け取った Logto 発行の元のユーザーアクセス トークン (Access token)。subject_token_type:urn:ietf:params:oauth:token-type:access_tokenを指定します。resource:API B のリソースインジケーター (Resource indicator)。scope:この委任呼び出しで API A が要求する下流の権限 (Permissions)。Logto は、RBAC 設定に従い、元のユーザーがこのリソースで利用可能なスコープ (Scope) のみを発行します。
Logto は API B 用のアクセス トークン (Access token) を返します:
{
"access_token": "eyJhbGci...<truncated>",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "read:orders"
}
デコードすると、アクセス トークン (Access token) には次のようなクレーム (Claims) が含まれます:
{
"sub": "user_id",
"client_id": "api_a_app_id",
"iss": "https://tenant.logto.app/oidc",
"aud": "https://api-b.example.com",
"scope": "read:orders",
"exp": 1760000000
}
その後、API A は交換済みトークンで API B を呼び出します:
GET /orders HTTP/1.1
Host: api-b.example.com
Authorization: Bearer <exchanged_access_token>
API B でトークンを検証する
API B は、Logto 発行の API リソース用アクセス トークン (Access token) と同様に、交換済みトークンを検証する必要があります:
- Logto の JWKs を使って署名を検証します。
- 発行者 (
iss) を確認します。 - オーディエンス (
aud) が API B のリソースインジケーター (Resource indicator) と一致するか確認します。 - 有効期限 (
exp) を確認します。 - 必要なスコープ (Scope) を確認します。
subを元のユーザー ID として利用します。- 特定の上流サービスのみ委任呼び出しを許可する場合は、
client_idも任意で確認します。
実装ガイダンスについては API でのアクセス トークン (Access token) の検証 を参照してください。
関連リソース
グローバル API リソースの保護API でのアクセス トークン (Access token) の検証
ユーザーなりすまし (User impersonation)