microsoft/semantic-kernel · error · ServiceInitializationError

No API key or Azure AD token available for ephemeral token r

Error message

No API key or Azure AD token available for ephemeral token request.

What it means

Raised by AzureRealtimeWebRTC._get_ephemeral_token_headers_and_url(). This method builds the auth headers for the ephemeral token request to the Azure Realtime client_secrets endpoint. It checks self.client.api_key (must be set and not the '<missing API key>' sentinel) and self.client._azure_ad_token (must be non-None). If neither is available, there is no credential to attach to the request. Notably, this method does NOT check for ad_token_provider — only static api_key and static ad_token are supported for ephemeral token retrieval.

Source

Thrown at python/semantic_kernel/connectors/ai/open_ai/services/azure_realtime.py:340

        url = f"{endpoint}/openai/v1/realtime/client_secrets"

        if self.client.api_key and self.client.api_key != "<missing API key>":
            return (
                {
                    "api-key": self.client.api_key,
                    "Content-Type": "application/json",
                },
                url,
            )
        if self.client._azure_ad_token is not None:  # type: ignore[attr-defined]
            return (
                {
                    "Authorization": f"Bearer {self.client._azure_ad_token}",  # type: ignore[attr-defined]
                    "Content-Type": "application/json",
                },
                url,
            )
        raise ServiceInitializationError("No API key or Azure AD token available for ephemeral token request.")

    @override
    async def _get_ephemeral_token(self) -> str:
        """Get an ephemeral token from Azure OpenAI.

        Azure GA requires a nested session object:
            {"session": {"type": "realtime", "model": "<deployment>"}}
        And returns the token directly as {"value": "..."} rather than
        OpenAI's {"client_secret": {"value": "..."}}.
        See: https://learn.microsoft.com/en-us/azure/ai-foundry/openai/how-to/realtime-audio-webrtc
        """
        data = {
            "session": {
                "type": "realtime",
                "model": self.ai_model_id,
            }
        }
        headers, url = self._get_ephemeral_token_headers_and_url()

View on GitHub (pinned to c028a0c7dc)

Solutions

  1. Provide an api_key when constructing AzureRealtimeWebRTC — the ephemeral token endpoint accepts key-based auth.
  2. Provide a static ad_token (pre-fetched Azure AD token string) instead of only an ad_token_provider.
  3. If you must use a token provider, pre-resolve the token yourself and pass it as ad_token=<resolved_token>.
  4. If using a pre-built client, ensure it was constructed with api_key= or azure_ad_token= (not just azure_ad_token_provider=).

Example fix

# before (token provider only — ephemeral token path cannot use it)
service = AzureRealtimeWebRTC(
    audio_track=my_track,
    endpoint='https://myresource.openai.azure.com',
    deployment_name='gpt-4o-realtime',
    ad_token_provider=my_provider_func,  # no static key or token
)
# after (pass api_key for ephemeral token auth)
service = AzureRealtimeWebRTC(
    audio_track=my_track,
    endpoint='https://myresource.openai.azure.com',
    deployment_name='gpt-4o-realtime',
    api_key=os.environ['AZURE_OPENAI_API_KEY'],
)
Defensive patterns

Strategy: validation

Validate before calling

def validate_webrtc_auth(api_key, ad_token, ad_token_provider, async_client):
    """The AzureRealtimeWebRTC ephemeral token path only supports static api_key or static ad_token.
    An ad_token_provider alone is not sufficient for the ephemeral token request."""
    if async_client is not None:
        # Client handles its own auth — but verify it has a key or static token
        return
    if not api_key and not ad_token:
        if ad_token_provider:
            raise ValueError(
                'AzureRealtimeWebRTC ephemeral token endpoint requires api_key or static ad_token. '
                'An ad_token_provider alone is not supported. Pre-resolve the token and pass as ad_token.'
            )
        raise ValueError('api_key or ad_token is required for AzureRealtimeWebRTC')

validate_webrtc_auth(api_key, ad_token, ad_token_provider, async_client)

Try / catch

from semantic_kernel.exceptions.service_exceptions import ServiceInitializationError

try:
    token = await service._get_ephemeral_token()
except ServiceInitializationError as e:
    if 'No API key or Azure AD token' in str(e):
        # Reconstruct the service with api_key or a pre-resolved ad_token
        print('WebRTC ephemeral token requires static api_key or ad_token, not a provider.')
    raise

Prevention

When it happens

Trigger: Constructing AzureRealtimeWebRTC with only an ad_token_provider (no static api_key, no static ad_token). The AsyncAzureOpenAI client is configured with a callable token provider, so client.api_key is unset and client._azure_ad_token is None at the time this method runs. Also possible if a pre-built async_client was passed that has neither a key nor a static token.

Common situations: Using Azure managed identity (DefaultAzureCredential with a token provider callback) for WebRTC realtime; passing a bare AsyncAzureOpenAI client built elsewhere that relies on a provider; migrating from key-based auth to Entra ID auth and forgetting that the WebRTC ephemeral-token path only checks static credentials.

Related errors


AI-assisted analysis of microsoft/semantic-kernel@c028a0c7dc (2026-08-13). Data as JSON: /api/errors/1a777155f61005fd. Report an issue: GitHub.