リアルタイム API でトークンを使用して接続を認証する方法、API キーの取得方法、および WebSocket、WebRTC、AOQ プロトコルでの認証方法について説明します。
リアルタイム API は認証に API キーを使用します。AOQ、WebRTC、または WebSocket のいずれを介して接続する場合でも、Authorization HTTP リクエストヘッダーでベアラートークンを渡します。
認証は接続の確立時にのみ行われます。接続が確立された後のデータ送信では、再認証は不要です。
次の表は、3 つのプロトコルの認証方法を比較したものです。
プロトコル | 認証が行われるタイミング | 認証方法 | 備考 |
|---|---|---|---|
AOQ | ビジネス AppServer がゲートウェイにリクエストする際 | HTTP ヘッダー | API キーはサーバーサイドでのみ使用されます。クライアントはゲートウェイから返されたトークンを使用します。 |
WebRTC | SDP 交換の HTTP リクエスト時 | HTTP ヘッダー | クライアントまたはサーバーが API キーを使用して SDP 交換を開始します。 |
WebSocket | WebSocket ハンドシェイク中 | HTTP ヘッダー | クライアントまたはサーバーが API キーを使用して直接接続します。 |
API キーの取得
ステップ 1:Model Studio の有効化
- Alibaba Cloud Model Studio コンソールに移動し、Alibaba Cloud アカウントでログインします。
- 初めてサービスをご利用になる場合は、画面の指示に従ってサービスを有効化してください。
ステップ 2:API キーの作成
- コンソールのナビゲーションペインで、[API Key] を選択します。
- [Create API Key] をクリックし、キーに関連付けるワークスペースを選択します。
- キーが作成されたら、すぐにコピーして安全な場所に保管してください。
重要セキュリティに関する注意:API キーは、サービスにアクセスするための唯一の認証情報です。クライアントコードにハードコーディングしたり、コードリポジトリにコミットしたりしないでください。環境変数で管理するか、バックエンドサービスから配布するようにしてください。
接続認証の詳細
AOQ プロトコル認証
AOQ はサーバーサイドプロキシ認証モデルを使用します。API キーはビジネス AppServer でのみ使用されます。クライアントはゲートウェイから返された一時的なトークンで接続するため、API キーがクライアント側に渡ることはありません。
curl -X POST \
"https://{endpoint}/api/v1/webrtc/realtime?model=qwen3.5-omni-plus-realtime" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${DASHSCOPE_API_KEY}" \
-H "x-dashscope-rtc-transport: moq" \
-d "{\"clientIp\": \"${CLIENT_REAL_IP}\"}"
curl -X POST \
"https://{endpoint}/api/v1/webrtc/inference?model=fun-asr-realtime" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${DASHSCOPE_API_KEY}" \
-H "x-dashscope-rtc-transport: moq" \
-d "{\"clientIp\": \"${CLIENT_REAL_IP}\"}"
リクエストフィールド
項目 | 値 | 説明 |
|---|---|---|
endpoint | ビジネスシナリオに応じて選択するアクセスドメイン | アクセスドメインを指定します。詳細については、「リージョンとアクセスドメイン」をご参照ください。 |
Content-Type |
| メッセージタイプを指定します |
Authorization |
| ご自身の API キー |
x-dashscope-rtc-transport |
| AOQ プロトコルを指定します |
clientIp | クライアントの実際のパブリック IP アドレス | オプション。指定しない場合、Model Studio ゲートウェイへのリクエスト元の IP アドレスが使用されます。指定した場合、 |
レスポンスの例
{
"sid": "1d06b55683db49bba67a407902f62d02:1782706970:69aecdc5...",
"aoqTokenForClient": "ecc1a46015d5496ca4ff7a48281eb739",
"clientRelayEndpoints": [{"endpoint": "121.199.XX.XX", "port": 8443, "route_index": 0}],
"clientRelayCertFingerprint": "sha256/99843495...",
"sidExpiresInSecs": 7200,
"extraInfo": {"workspaceIdHash": "2021b6f98cea4cff"}
}
レスポンスフィールド
フィールド | 説明 |
|---|---|
sid | 一意のセッション ID |
aoqTokenForClient | クライアント接続トークン。SDK の |
clientRelayEndpoints | Relay アクセスポイント (endpoint + port) の配列 |
clientRelayCertFingerprint | Relay TLS 証明書のフィンガープリント |
sidExpiresInSecs | セッションの有効期限 (秒) |
extraInfo.workspaceIdHash | ワークスペース ID のハッシュ |
AOQ クライアント SDK 接続の例
注記clientIp は、リクエストボディ内の省略可能なフィールドです。指定されていない場合、Model Studio ゲートウェイにリクエストする IP アドレスがクライアント IP として使用されます。指定された場合、clientIp の値が優先されます。最適なリレーアクセスポイントを取得するには、お使いのビジネス AppServer でクライアントの実際の IP アドレスを取得し、渡してください。
let resp = try JSONDecoder().decode(AllocateResponse.self, from: responseData)
let config = AoqConnectConfig()
config.token = resp.aoqTokenForClient
config.sid = resp.sid
config.certFingerprint = resp.clientRelayCertFingerprint
config.relayEndpoints = resp.clientRelayEndpoints.enumerated().map { index, item in
let ep = AoqRelayEndpoint()
// route_index がない場合は、配列のインデックスにフォールバックします
ep.routeIndex = item.routeIndex ?? index
ep.endpoint = item.endpoint
ep.port = item.port
return ep
}
config.workspaceIdHash = resp.extraInfo?.workspaceIdHash ?? ""
let audioTrack = AoqTrackParam()
audioTrack.trackType = .audio
let dataTrack = AoqTrackParam()
dataTrack.trackType = .data
config.publishTracks = [audioTrack, dataTrack]
config.subscribeTracks = [audioTrack, dataTrack]
engine.connect(config)
JSONObject obj = new JSONObject(responseText);
AoqClientEngine.AoqConnectConfig cfg = new AoqClientEngine.AoqConnectConfig();
cfg.token = obj.optString("aoqTokenForClient", "");
cfg.sid = obj.optString("sid", "");
cfg.certFingerprint = obj.optString("clientRelayCertFingerprint", "");
JSONArray arr = obj.optJSONArray("clientRelayEndpoints");
if (arr != null) {
for (int i = 0; i < arr.length(); i++) {
JSONObject o = arr.optJSONObject(i);
AoqClientEngine.AoqRelayEndpoint ep = new AoqClientEngine.AoqRelayEndpoint();
// route_index がない場合は、配列のインデックスにフォールバックします
ep.routeIndex = o.has("route_index") ? o.optInt("route_index", i) : i;
ep.endpoint = o.optString("endpoint", "");
ep.port = o.optInt("port", 0);
cfg.relayEndpoints.add(ep);
}
}
JSONObject ext = obj.optJSONObject("extraInfo");
cfg.workspaceIdHash = ext != null ? ext.optString("workspaceIdHash", "") : "";
AoqClientEngine.AoqTrackParam audio = new AoqClientEngine.AoqTrackParam();
audio.trackType = AoqClientEngine.AoqTrackType.AoqTrackTypeAudio;
AoqClientEngine.AoqTrackParam data = new AoqClientEngine.AoqTrackParam();
data.trackType = AoqClientEngine.AoqTrackType.AoqTrackTypeData;
cfg.publishTracks.add(audio);
cfg.publishTracks.add(data);
cfg.subscribeTracks.add(audio);
cfg.subscribeTracks.add(data);
engine.connect(cfg);
const obj = JSON.parse(responseText) as Record<string, Object | undefined>;
const cfg: AoqConnectConfig = {
token: String(obj['aoqTokenForClient'] ?? ''),
sid: String(obj['sid'] ?? ''),
certFingerprint: String(obj['clientRelayCertFingerprint'] ?? ''),
// route_index がない場合は、配列のインデックスにフォールバックします
relayEndpoints: (obj['clientRelayEndpoints'] as Array<any>).map((item, index) => ({
routeIndex: Number(item['route_index'] ?? index),
endpoint: String(item['endpoint'] ?? ''),
port: Number(item['port'] ?? 0)
})),
workspaceIdHash: String((obj['extraInfo'] as any)?.['workspaceIdHash'] ?? ''),
publishTracks: [
{ trackType: AoqTrackType.AoqTrackTypeAudio },
{ trackType: AoqTrackType.AoqTrackTypeData }
],
subscribeTracks: [
{ trackType: AoqTrackType.AoqTrackTypeAudio },
{ trackType: AoqTrackType.AoqTrackTypeData }
]
};
engine.connect(cfg);
WebRTC プロトコル認証
WebRTC は、HTTP POST リクエストを介して SDP 交換を完了し、認証はこの段階で行われます。クライアントは Offer SDP をサーバーに送信し、サーバーは Answer SDP を返します。
項目 | 値 | 説明 |
|---|---|---|
リクエストメソッド | POST | - |
リクエスト URL |
|
|
Content-Type |
| リクエストボディは SDP 文字列です。 |
Authorization |
| ご自身の API キー |
レスポンス | Answer SDP を含む HTTP 200 | 失敗した場合は 4xx ステータスコードを返します。 |
const pc = new RTCPeerConnection();
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
stream.getAudioTracks().forEach(t => pc.addTrack(t, stream));
pc.createDataChannel('oai-events');
const offer = await pc.createOffer();
await pc.setLocalDescription(offer);
// ICE GATHERING が完了した後に送信します
const resp = await fetch(API_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/sdp',
'Authorization': `Bearer ${API_KEY}`,
},
body: pc.localDescription.sdp,
});
const answerSdp = await resp.text();
await pc.setRemoteDescription({ type: 'answer', sdp: answerSdp });
WebSocket プロトコル認証
WebSocket の認証は最もシンプルです。接続を確立する際に、HTTP ヘッダーで API キーを送信します。
項目 | 値 | 説明 |
|---|---|---|
接続 URL |
| 接続 URL はモデルによって異なります。詳細については、「WebSocket 接続」をご参照ください。 |
Authorization |
| ご自身の API キー |
import websocket, os
API_KEY = os.getenv("DASHSCOPE_API_KEY")
URL = "wss://dashscope.aliyuncs.com/api-ws/v1/realtime?model=qwen3.5-omni-plus-realtime"
ws = websocket.WebSocketApp(URL, header=["Authorization: Bearer " + API_KEY])
ws.run_forever()