Skip to content

🤖 feat: add Azure Entra ID keyless auth for OpenAI provider#2428

Open
ibetitsmike wants to merge 4 commits intomainfrom
mike/entra-auth
Open

🤖 feat: add Azure Entra ID keyless auth for OpenAI provider#2428
ibetitsmike wants to merge 4 commits intomainfrom
mike/entra-auth

Conversation

@ibetitsmike
Copy link
Contributor

Summary

Adds Azure Entra ID (Microsoft identity) keyless authentication as a new auth path for the OpenAI provider. Enterprise Azure deployments can now use DefaultAzureCredential (via az login, managed identity, or workload identity) instead of distributing API keys.

Background

Enterprise customers deploying Azure OpenAI often rely on Azure Entra ID for authentication rather than API keys. This enables tighter security controls (no long-lived secrets), compliance with corporate identity policies, and seamless integration with Azure managed identity on cloud workloads.

The implementation reuses the existing openai provider namespace — no new provider or model migration needed. Auth priority is preserved: API key → Codex OAuth → Entra keyless → error.

Implementation

Core auth flow (providerModelFactory.ts):

  • Added lazy-loaded Entra token provider using @azure/identity (DefaultAzureCredential + getBearerTokenProvider)
  • Wraps fetch to inject Authorization: Bearer <token> and remove x-api-key header
  • Token caching/refresh handled by the Azure SDK internally
  • Inserted after Codex OAuth check in the auth decision chain

Credential resolver (providerRequirements.ts):

  • OpenAI marked as configured when authMode=entra + baseUrl present, no API key required
  • Supports both config (providers.jsonc) and env vars (OPENAI_AUTH_MODE=entra + OPENAI_BASE_URL)
  • API key always takes precedence when present

Schema + service (api.ts, providerService.ts):

  • Added openaiAuthMode: "apiKey" | "entra" field to ProviderConfigInfoSchema
  • Provider service surfaces auth mode to frontend

UI (ProvidersSection.tsx):

  • Auth mode selector in OpenAI provider settings (API Key / Azure Entra ID)
  • Uses existing updateOptimistically persistence pattern

Docs (providers.mdx, gen_docs.ts):

  • Setup guide for keyless mode with config and env examples
  • Doc generator updated to include OPENAI_AUTH_MODE in env var table

Validation

  • make static-check — all checks pass (typecheck, lint, fmt, docs links, eager imports)
  • New tests for resolver, provider service, and model factory cover Entra mode, API key precedence, and edge cases

Risks

  • Low severity: @azure/identity is lazily loaded only when authMode=entra — no impact on non-Azure users (no startup cost, no bundle bloat for users who don't use it)
  • Low severity: Entra token acquisition requires valid Azure credentials in the environment. Clear errors from DefaultAzureCredential surface when credentials are missing.

Generated with mux • Model: anthropic:claude-opus-4-6 • Thinking: xhigh • Cost: $1.20

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d2e0c3b7e2

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

if (codexOauthRequired && !storedCodexOauth && !creds.isConfigured) {
// fall back to their API key instead of blocking entirely. If no API key
// exists, surface the OAuth setup requirement.
if (codexOauthRequired && !storedCodexOauth && !creds.apiKey) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Allow Entra fallback for Codex-required models

createModel now returns oauth_not_connected whenever a Codex-required model has no stored OAuth and no creds.apiKey, which also blocks OpenAI configs that are otherwise configured via Entra (authMode=entra + baseUrl). In that scenario resolveProviderCredentials reports configured credentials, but this guard exits before Entra fallback is evaluated, so requests for required Codex models fail immediately despite the new keyless auth path being present.

Useful? React with 👍 / 👎.

init?: Parameters<typeof fetch>[1]
): Promise<Response> => {
const tokenProvider = await getEntraBearerTokenProvider();
const token = await tokenProvider();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Propagate AbortSignal into Entra token acquisition

wrapFetchWithOpenAIEntraAuth calls tokenProvider() without passing through init.signal, so request cancellation cannot interrupt DefaultAzureCredential token acquisition. When identity endpoints are slow or unreachable, users can abort the chat request in the UI but this auth step will still block until credential timeouts complete, which breaks expected cancellation behavior.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant