{"record":{"id":"1a777155f61005fd","repo":"microsoft/semantic-kernel","slug":"no-api-key-or-azure-ad-token-available-for-ephemer","errorCode":null,"errorMessage":"No API key or Azure AD token available for ephemeral token request.","messagePattern":"No API key or Azure AD token available for ephemeral token request\\.","errorType":"exception","errorClass":"ServiceInitializationError","httpStatus":null,"severity":"error","filePath":"python/semantic_kernel/connectors/ai/open_ai/services/azure_realtime.py","lineNumber":340,"sourceCode":"        url = f\"{endpoint}/openai/v1/realtime/client_secrets\"\n\n        if self.client.api_key and self.client.api_key != \"<missing API key>\":\n            return (\n                {\n                    \"api-key\": self.client.api_key,\n                    \"Content-Type\": \"application/json\",\n                },\n                url,\n            )\n        if self.client._azure_ad_token is not None:  # type: ignore[attr-defined]\n            return (\n                {\n                    \"Authorization\": f\"Bearer {self.client._azure_ad_token}\",  # type: ignore[attr-defined]\n                    \"Content-Type\": \"application/json\",\n                },\n                url,\n            )\n        raise ServiceInitializationError(\"No API key or Azure AD token available for ephemeral token request.\")\n\n    @override\n    async def _get_ephemeral_token(self) -> str:\n        \"\"\"Get an ephemeral token from Azure OpenAI.\n\n        Azure GA requires a nested session object:\n            {\"session\": {\"type\": \"realtime\", \"model\": \"<deployment>\"}}\n        And returns the token directly as {\"value\": \"...\"} rather than\n        OpenAI's {\"client_secret\": {\"value\": \"...\"}}.\n        See: https://learn.microsoft.com/en-us/azure/ai-foundry/openai/how-to/realtime-audio-webrtc\n        \"\"\"\n        data = {\n            \"session\": {\n                \"type\": \"realtime\",\n                \"model\": self.ai_model_id,\n            }\n        }\n        headers, url = self._get_ephemeral_token_headers_and_url()","sourceCodeStart":322,"sourceCodeEnd":358,"githubUrl":"https://github.com/microsoft/semantic-kernel/blob/c028a0c7dc4f0814cdcbaba9d998f187a41197bf/python/semantic_kernel/connectors/ai/open_ai/services/azure_realtime.py#L322-L358","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Provide an api_key when constructing AzureRealtimeWebRTC — the ephemeral token endpoint accepts key-based auth.","Provide a static ad_token (pre-fetched Azure AD token string) instead of only an ad_token_provider.","If you must use a token provider, pre-resolve the token yourself and pass it as ad_token=<resolved_token>.","If using a pre-built client, ensure it was constructed with api_key= or azure_ad_token= (not just azure_ad_token_provider=)."],"exampleFix":"# before (token provider only — ephemeral token path cannot use it)\nservice = AzureRealtimeWebRTC(\n    audio_track=my_track,\n    endpoint='https://myresource.openai.azure.com',\n    deployment_name='gpt-4o-realtime',\n    ad_token_provider=my_provider_func,  # no static key or token\n)\n# after (pass api_key for ephemeral token auth)\nservice = AzureRealtimeWebRTC(\n    audio_track=my_track,\n    endpoint='https://myresource.openai.azure.com',\n    deployment_name='gpt-4o-realtime',\n    api_key=os.environ['AZURE_OPENAI_API_KEY'],\n)","handlingStrategy":"validation","validationCode":"def validate_webrtc_auth(api_key, ad_token, ad_token_provider, async_client):\n    \"\"\"The AzureRealtimeWebRTC ephemeral token path only supports static api_key or static ad_token.\n    An ad_token_provider alone is not sufficient for the ephemeral token request.\"\"\"\n    if async_client is not None:\n        # Client handles its own auth — but verify it has a key or static token\n        return\n    if not api_key and not ad_token:\n        if ad_token_provider:\n            raise ValueError(\n                'AzureRealtimeWebRTC ephemeral token endpoint requires api_key or static ad_token. '\n                'An ad_token_provider alone is not supported. Pre-resolve the token and pass as ad_token.'\n            )\n        raise ValueError('api_key or ad_token is required for AzureRealtimeWebRTC')\n\nvalidate_webrtc_auth(api_key, ad_token, ad_token_provider, async_client)","typeGuard":null,"tryCatchPattern":"from semantic_kernel.exceptions.service_exceptions import ServiceInitializationError\n\ntry:\n    token = await service._get_ephemeral_token()\nexcept ServiceInitializationError as e:\n    if 'No API key or Azure AD token' in str(e):\n        # Reconstruct the service with api_key or a pre-resolved ad_token\n        print('WebRTC ephemeral token requires static api_key or ad_token, not a provider.')\n    raise","preventionTips":["Pass api_key when using AzureRealtimeWebRTC — the ephemeral token path checks static credentials only.","If using Entra ID, pre-resolve the token with get_entra_auth_token() and pass it as ad_token=.","Avoid relying solely on ad_token_provider for WebRTC realtime.","If passing a pre-built client, ensure it has api_key= or azure_ad_token= set (not just azure_ad_token_provider=)."],"tags":["azure-openai","realtime","webrtc","authentication","ephemeral-token"],"backgroundTag":null,"analyzedSha":"c028a0c7dc4f0814cdcbaba9d998f187a41197bf","analyzedAt":"2026-08-13T13:48:05.040Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}