Microsoft Entra ID Auth SDK (サイドカー) の /AuthorizationHeader エンドポイントを使用して、受信したベアラー トークンを、ダウンストリーム API を対象とする認可ヘッダーに交換します。 この方法では、トークンの取得を SDK に委任しながら、HTTP 要求を完全に制御できます。
[前提条件]
- アクティブなサブスクリプションを持つAzure アカウント。 無料でアカウントを作成できます。
- Microsoft Entra ID Auth SDK (サイドカー) がデプロイされ、環境内で実行されています。 セットアップ手順については 、インストール ガイド を参照してください。
- ベース URL とトークン交換に必要なスコープを使用して SDK で構成されたダウンストリーム API。
- 認証されたクライアントからのベアラー トークン - アプリケーションは、ダウンストリーム API トークンと交換するクライアント アプリケーションからトークンを受け取ります。
- Microsoft Entra ID のアクセス許可を適用する - アカウントには、アプリケーションを登録し、API アクセス許可を付与するためのアクセス許可が必要です。
コンフィギュレーション
ベース URL、必要なスコープ、およびオプションの相対パスを使用して、Microsoft Entra ID Auth SDK (サイドカー) でダウンストリーム API を構成します。
env:
- name: DownstreamApis__Graph__BaseUrl
value: "https://graph.microsoft.com/v1.0"
- name: DownstreamApis__Graph__Scopes
value: "User.Read Mail.Read"
TypeScript/Node.js
Microsoft Entra ID認証 SDK (サイドカー) を呼び出し、承認ヘッダーを取得する TypeScript 関数を作成します。 その後、HTTP クライアントでこのヘッダーを使用して、ダウンストリーム API を呼び出すことができます。
import fetch from 'node-fetch';
interface AuthHeaderResponse {
authorizationHeader: string;
}
async function getAuthorizationHeader(
incomingToken: string,
serviceName: string
): Promise<string> {
const sidecarUrl = process.env.SIDECAR_URL || 'http://localhost:5000';
const response = await fetch(
`${sidecarUrl}/AuthorizationHeader/${serviceName}`,
{
headers: {
'Authorization': incomingToken
}
}
);
if (!response.ok) {
throw new Error(`Failed to get authorization header: ${response.statusText}`);
}
const data = await response.json() as AuthHeaderResponse;
return data.authorizationHeader;
}
// Usage example
async function getUserProfile(incomingToken: string) {
// Get authorization header for Microsoft Graph
const authHeader = await getAuthorizationHeader(incomingToken, 'Graph');
// Use the authorization header to call Microsoft Graph
const graphResponse = await fetch(
'https://graph.microsoft.com/v1.0/me',
{
headers: {
'Authorization': authHeader
}
}
);
return await graphResponse.json();
}
次の例では、ミドルウェアとルート ハンドラーを使用して、この関数を Express.js アプリケーションに統合する方法を示します。
// Express.js middleware example
import express from 'express';
const app = express();
app.get('/api/profile', async (req, res) => {
try {
const incomingToken = req.headers.authorization;
if (!incomingToken) {
return res.status(401).json({ error: 'No authorization token provided' });
}
const profile = await getUserProfile(incomingToken);
res.json(profile);
} catch (error) {
console.error('Error fetching profile:', error);
res.status(500).json({ error: 'Failed to fetch profile' });
}
});
Python
次のスニペットは、Microsoft Entra ID認証 SDK (サイドカー) を呼び出し、承認ヘッダーを取得するPython関数を示しています。
import os
import requests
from typing import Dict, Any
def get_authorization_header(incoming_token: str, service_name: str) -> str:
"""Get an authorization header from the SDK."""
sidecar_url = os.getenv('SIDECAR_URL', 'http://localhost:5000')
response = requests.get(
f"{sidecar_url}/AuthorizationHeader/{service_name}",
headers={'Authorization': incoming_token}
)
if not response.ok:
raise Exception(f"Failed to get authorization header: {response.text}")
data = response.json()
return data['authorizationHeader']
def get_user_profile(incoming_token: str) -> Dict[str, Any]:
"""Get user profile from Microsoft Graph."""
# Get authorization header for Microsoft Graph
auth_header = get_authorization_header(incoming_token, 'Graph')
# Use the authorization header to call Microsoft Graph
graph_response = requests.get(
'https://graph.microsoft.com/v1.0/me',
headers={'Authorization': auth_header}
)
if not graph_response.ok:
raise Exception(f"Graph API error: {graph_response.text}")
return graph_response.json()
この関数を Flask アプリケーションに統合する場合は、次の例を使用できます。
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route('/api/profile')
def profile():
incoming_token = request.headers.get('Authorization')
if not incoming_token:
return jsonify({'error': 'No authorization token provided'}), 401
try:
profile_data = get_user_profile(incoming_token)
return jsonify(profile_data)
except Exception as e:
print(f"Error fetching profile: {e}")
return jsonify({'error': 'Failed to fetch profile'}), 500
if __name__ == '__main__':
app.run(port=8080)
Go
次に、Microsoft Entra ID認証 SDK (サイドカー) を呼び出し、承認ヘッダーを取得する Go 関数を示します。 この実装では、JSON 応答を解析し、ヘッダーを使用する方法を示します。
package main
import (
"encoding/json"
"fmt"
"io"
"net/http"
"os"
)
type AuthHeaderResponse struct {
AuthorizationHeader string `json:"authorizationHeader"`
}
type UserProfile struct {
DisplayName string `json:"displayName"`
Mail string `json:"mail"`
UserPrincipalName string `json:"userPrincipalName"`
}
func getAuthorizationHeader(incomingToken, serviceName string) (string, error) {
sidecarURL := os.Getenv("SIDECAR_URL")
if sidecarURL == "" {
sidecarURL = "http://localhost:5000"
}
url := fmt.Sprintf("%s/AuthorizationHeader/%s", sidecarURL, serviceName)
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return "", err
}
req.Header.Set("Authorization", incomingToken)
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return "", err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(resp.Body)
return "", fmt.Errorf("failed to get authorization header: %s", string(body))
}
var authResp AuthHeaderResponse
if err := json.NewDecoder(resp.Body).Decode(&authResp); err != nil {
return "", err
}
return authResp.AuthorizationHeader, nil
}
func getUserProfile(incomingToken string) (*UserProfile, error) {
// Get authorization header for Microsoft Graph
authHeader, err := getAuthorizationHeader(incomingToken, "Graph")
if err != nil {
return nil, err
}
// Use the authorization header to call Microsoft Graph
req, err := http.NewRequest("GET", "https://graph.microsoft.com/v1.0/me", nil)
if err != nil {
return nil, err
}
req.Header.Set("Authorization", authHeader)
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(resp.Body)
return nil, fmt.Errorf("Graph API error: %s", string(body))
}
var profile UserProfile
if err := json.NewDecoder(resp.Body).Decode(&profile); err != nil {
return nil, err
}
return &profile, nil
}
// HTTP handler example
func profileHandler(w http.ResponseWriter, r *http.Request) {
incomingToken := r.Header.Get("Authorization")
if incomingToken == "" {
http.Error(w, "No authorization token provided", http.StatusUnauthorized)
return
}
profile, err := getUserProfile(incomingToken)
if err != nil {
fmt.Printf("Error fetching profile: %v\n", err)
http.Error(w, "Failed to fetch profile", http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(profile)
}
func main() {
http.HandleFunc("/api/profile", profileHandler)
fmt.Println("Server starting on :8080")
http.ListenAndServe(":8080", nil)
}
C# の実装
Microsoft Entra ID認証 SDK (サイドカー) を呼び出して承認ヘッダーを取得する C# クラスを作成します。 この実装では、ASP.NET Coreの依存関係の挿入を使用します。
using System;
using System.Net.Http;
using System.Net.Http.Json;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
public class SidecarClient
{
private readonly HttpClient _httpClient;
private readonly string _sidecarUrl;
public SidecarClient(IHttpClientFactory httpClientFactory, IConfiguration config)
{
_httpClient = httpClientFactory.CreateClient();
_sidecarUrl = config["SIDECAR_URL"] ?? "http://localhost:5000";
}
public async Task<string> GetAuthorizationHeaderAsync(
string incomingAuthorizationHeader,
string serviceName)
{
var request = new HttpRequestMessage(
HttpMethod.Get,
$"{_sidecarUrl}/AuthorizationHeader/{serviceName}"
);
request.Headers.Add("Authorization", incomingAuthorizationHeader);
var response = await _httpClient.SendAsync(request);
response.EnsureSuccessStatusCode();
var result = await response.Content.ReadFromJsonAsync<AuthHeaderResponse>();
return result.AuthorizationHeader;
}
}
public record AuthHeaderResponse(string AuthorizationHeader);
public record UserProfile(string DisplayName, string Mail, string UserPrincipalName);
// Controller example
[ApiController]
[Route("api/[controller]")]
public class ProfileController : ControllerBase
{
private readonly SidecarClient _sidecarClient;
private readonly HttpClient _httpClient;
public ProfileController(SidecarClient sidecarClient, IHttpClientFactory httpClientFactory)
{
_sidecarClient = sidecarClient;
_httpClient = httpClientFactory.CreateClient();
}
[HttpGet]
public async Task<ActionResult<UserProfile>> GetProfile()
{
var incomingToken = Request.Headers["Authorization"].ToString();
if (string.IsNullOrEmpty(incomingToken))
{
return Unauthorized("No authorization token provided");
}
try
{
// Get authorization header for Microsoft Graph
var authHeader = await _sidecarClient.GetAuthorizationHeaderAsync(
incomingToken,
"Graph"
);
// Use the authorization header to call Microsoft Graph
var request = new HttpRequestMessage(
HttpMethod.Get,
"https://graph.microsoft.com/v1.0/me"
);
request.Headers.Add("Authorization", authHeader);
var response = await _httpClient.SendAsync(request);
response.EnsureSuccessStatusCode();
var profile = await response.Content.ReadFromJsonAsync<UserProfile>();
return Ok(profile);
}
catch (Exception ex)
{
return StatusCode(500, $"Failed to fetch profile: {ex.Message}");
}
}
}
高度なシナリオ
Microsoft Entra ID認証 SDK (サイドカー) では、クエリ パラメーターを使用していくつかの高度なパターンがサポートされています。
スコープをオーバーライドする
構成とは異なる特定のスコープを要求します。
const response = await fetch(
`${sidecarUrl}/AuthorizationHeader/Graph?` +
`optionsOverride.Scopes=User.Read&` +
`optionsOverride.Scopes=Mail.Send`,
{
headers: { 'Authorization': incomingToken }
}
);
マルチテナントのサポート
特定のユーザーのテナントをオーバーライドします。
const response = await fetch(
`${sidecarUrl}/AuthorizationHeader/Graph?` +
`optionsOverride.AcquireTokenOptions.Tenant=${userTenantId}`,
{
headers: { 'Authorization': incomingToken }
}
);
アプリケーション トークンを要求する
OBO の代わりにアプリケーション トークンを要求します。
const response = await fetch(
`${sidecarUrl}/AuthorizationHeader/Graph?` +
`optionsOverride.RequestAppToken=true`,
{
headers: { 'Authorization': incomingToken }
}
);
エージェント ID を用いた認証
委任にエージェント ID を使用します。
const response = await fetch(
`${sidecarUrl}/AuthorizationHeader/Graph?` +
`AgentIdentity=${agentClientId}&` +
`AgentUsername=${encodeURIComponent(userPrincipalName)}`,
{
headers: { 'Authorization': incomingToken }
}
);
エラー処理
一時的な障害と永続的な障害を区別するために、Microsoft Entra ID認証 SDK (サイドカー) を呼び出すときに、適切なエラー処理を実装します。
一時的なエラーを処理する
一時的な障害に対して指数バックオフを使用して再試行ロジックを実装します。
async function getAuthorizationHeaderWithRetry(
incomingToken: string,
serviceName: string,
maxRetries = 3
): Promise<string> {
let lastError: Error;
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const response = await fetch(
`${sidecarUrl}/AuthorizationHeader/${serviceName}`,
{
headers: { 'Authorization': incomingToken }
}
);
if (response.ok) {
const data = await response.json();
return data.authorizationHeader;
}
// Don't retry on 4xx errors (client errors)
if (response.status >= 400 && response.status < 500) {
const error = await response.json();
throw new Error(`Client error: ${error.detail || response.statusText}`);
}
// Retry on 5xx errors (server errors)
lastError = new Error(`Server error: ${response.statusText}`);
if (attempt < maxRetries) {
// Exponential backoff
await new Promise(resolve =>
setTimeout(resolve, Math.pow(2, attempt) * 100)
);
}
} catch (error) {
lastError = error as Error;
if (attempt < maxRetries) {
await new Promise(resolve =>
setTimeout(resolve, Math.pow(2, attempt) * 100)
);
}
}
}
throw new Error(`Failed after ${maxRetries} retries: ${lastError.message}`);
}
ベスト プラクティス
Microsoft Entra ID認証 SDK (サイドカー) から承認ヘッダーを取得する場合は、次のプラクティスに従います。
- HTTP クライアントの再利用: 1 つの HTTP クライアント インスタンスを作成し、呼び出しごとに新しいクライアントを作成するのではなく、要求間で再利用します。 これにより、パフォーマンスが向上し、接続プールが有効になります。
- エラーを適切に処理する: 一時的なエラー (5xx エラー) の再試行ロジックを実装しますが、構成の問題を示すクライアント エラー (4xx 応答) では直ちに失敗します。
- 適切なタイムアウトの設定: 予想される待機時間に基づいて SDK 呼び出しのタイムアウトを構成します。 これにより、SDK が応答しない場合にアプリケーションがハングするのを防ぐことができます。
- キャッシュ承認ヘッダー: SDK への不要な呼び出しを減らすために、キャッシュは有効期間中に返されたヘッダーをキャッシュします。 キャッシュ時にトークンの有効期限を尊重します。
- ログ関連付け ID: SDK 応答からの関連付け ID をログに含めて、システム境界を越えた要求トレースを有効にします。
- 応答の検証: 承認ヘッダーを使用する前に、常に応答状態コードを確認し、必須フィールドが存在することを検証します。
関連するコンテンツ
- ダウンストリーム API を呼び出す
- 承認ヘッダーを検証する
- TypeScript からの使用
Python からの使用