Skip to content

feat(auth): add X.509 workload identity federation for HTTP - #3622

Open
jbeckwith-oai wants to merge 11 commits into
mainfrom
codex/x509-workload-identity
Open

feat(auth): add X.509 workload identity federation for HTTP#3622
jbeckwith-oai wants to merge 11 commits into
mainfrom
codex/x509-workload-identity

Conversation

@jbeckwith-oai

@jbeckwith-oai jbeckwith-oai commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

What and why

Implement Phase 1 (HTTP only) of X.509 Workload Identity Federation in OpenAI SDKs: Design Proposal. Customers can exchange workload identity established by their existing mutually authenticated HTTP transport for an OpenAI access token without introducing SDK-owned certificates, private keys, token providers, or a configurable token endpoint.

Both OpenAI and AsyncOpenAI support the same additive, typed public API:

from openai import OpenAI
from openai.auth import x509_workload_identity

client = OpenAI(
    workload_identity=x509_workload_identity(
        identity_provider_id="idp_...",
        service_account_id="svc_acct_...",
    ),
    http_client=caller_configured_mtls_http_client,
)

refresh_buffer_seconds is optional. WorkloadIdentity remains the existing callable, backward-compatible subject-token TypedDict; both OpenAI and AsyncOpenAI accept the explicit typed union WorkloadIdentity | X509WorkloadIdentity. SubjectTokenWorkloadIdentity is a compatibility alias, and the public WorkloadIdentityAuth constructor remains narrowed to subject-token identities. The helper name, snake_case options, TypedDict configuration, SDK exception types, injected-client lifecycle, typed copy()/with_options(), and explicit sync/async implementations follow neighboring Python SDK patterns. Azure/Bedrock overriding copy signatures retain Python-compatible parameter variance without changing their provider authentication behavior. Async refresh uses AnyIO-compatible locking and sleep; it never runs an asynchronous exchange through blocking thread work.

Security, transport ownership, and compatibility

  • Exchange tokens only with POST https://mtls.auth.openai.com/oauth/token; the JSON structurally omits subject_token, the exchange URL is not public configuration, and redirects are disabled per request.
  • Reuse the effective caller-configured HTTPX2 or legacy HTTPX client for the exchange and the subsequent API request. Certificate chains, private keys, passphrases, trust, proxies, HSM integration, pooling, and rotation remain entirely owned by that native transport.
  • Never mutate caller transport settings, retain certificate/key material, or include token/provider-controlled error details in exceptions or logs. Preserve the SDK's existing HTTP-client close/aclose ownership behavior.
  • Use monotonic, bounded token caching with positive finite expires_in validation, half-TTL refresh-buffer clamping, sync and async single-flight refresh, cancellation-safe async waiters, bounded transient retries, and Retry-After handling.
  • Invalidate once after a 401 and replay only genuinely replayable requests. Seekable uploads are rewound to their original offsets; one-shot upload streams and non-replayable bodies are never replayed.
  • Default only X.509-mode clients without an explicit/environment base URL to https://mtls.api.openai.com/v1. Existing API-key authentication, JWT/ID-token workload identity, their separate exchange client, explicit base URLs, Python support policy, and dependency set are unchanged.
  • Realtime/WebSockets are explicitly excluded; they belong to Phase 2.

Verification

Gate Result
Full OpenAPI-mock-backed suite, Python 3.10 7,255 passed, 31 skipped against a dedicated healthy local Steady OpenAPI mock
Built-wheel auth/client/X.509 matrix, Python 3.11 7,255 passed, 31 skipped for the complete installed-wheel suite, including HTTPX2/aiohttp/Azure/Bedrock regressions
Built-wheel auth/client/X.509 matrix, Python 3.12 7,255 passed, 31 skipped for the complete installed-wheel suite, including HTTPX2/aiohttp/Azure/Bedrock regressions
Built-wheel auth/client/X.509 matrix, Python 3.13 7,255 passed, 31 skipped for the complete installed-wheel suite, including HTTPX2/aiohttp/Azure/Bedrock regressions
Built-wheel auth/client/X.509 matrix, Python 3.14 7,255 passed, 31 skipped for the complete installed-wheel suite, including HTTPX2/aiohttp/Azure/Bedrock regressions
Dedicated legacy HTTPX compatibility lane, Python 3.10 130 passed
Repository ./scripts/lint Passed: Ruff, whole-project Pyright (0 errors/0 warnings), whole-project mypy (1,547 source files), import validation
Ruff checks Passed: ruff check .; changed-file formatting; 1,717 repository files format-clean after excluding one independently verified, untouched upstream baseline defect
Documentation/example checks Passed: README documentation lint; auth/example/test compileall; both examples construct offline in API-key and X.509 modes
Source/wheel build Passed: python -m build --no-isolation
HTTPX2 wheel validator Passed: HTTPX2-only 20 passed/2 skipped, aiohttp 4 passed, isolated legacy HTTPX/aiohttp 3 passed
Python-version wheel, Bedrock wheel, and support-policy validators Passed; supported release matrix Python 3.10–3.14 and prerelease 3.15
Patch hygiene Passed: git diff --check; exact fourteen-path branch diff and clean committed worktree

The focused X.509 tests cover exact host/path/body and absence of subject_token, redirect refusal, transport/certificate ownership, transient retries and Retry-After, sync/async concurrency and cancellation, invalid/expired token responses and refresh windows, replayable versus one-shot upload/body behavior, safe error redaction, and API-key/JWT/ID-token regressions.

Formatting baseline disclosure: the unmodified upstream src/openai/resources/responses/responses.py already fails a whole-repository ruff format --check . on the exact base revision. The repository's actual ./scripts/lint, every changed file, and the other 1,717 files all pass; this PR intentionally does not modify unrelated generated code.

Maintainability and Python idiom review

The required strict thermo-nuclear-code-quality-review was completed against the complete exact fourteen-file publication diff: no structural blockers. X.509 logic is isolated in one 269-line handwritten auth module; neither new production nor test files exceed 1,000 lines. Mode selection occurs once in each existing sync/async constructor, subject-token and X.509 implementations share one properly initialized generic auth/cache base without identity casts, existing auth/retry/error layers remain canonical, and sync/async differences stay explicit.

The Python idiom review compared neighboring auth TypedDict/provider helpers, OpenAI/AsyncOpenAI injection and ownership, HTTPX/HTTPX2 request semantics, AnyIO cancellation, native SSLContext/transport boundaries, existing exception chaining/retry constants, pytest fixture style, and README examples. The result preserves established Python SDK naming, caller-client lifecycle, sync/async parity, and existing auth behavior without cross-language builder abstractions or hidden transport mutation.

Refreshed upstream base: 10ee3f0da2ac6f93345c1204bd7bb1a2faa79ff2

Validated publication head: 9512899eb98aab917ec9cf4c59342c77eb45c394

Prior independent installed-artifact mTLS validation

Built the exact committed wheel with .venv/bin/python -m build --no-isolation --outdir /private/tmp/openai-python-x509-round3-dist, installed that wheel into a clean temporary virtual environment, and executed /private/tmp/openai-python-x509-round3-venv/bin/python /private/tmp/openai-python-x509-second-round-e2e.py from outside the repository. The harness generates an ephemeral CA plus fresh server/client certificates, requires and verifies client-certificate presentation on every local HTTPS request, and connects the unmodified native HTTPX2 transport to the exact pinned authentication and API origins through a hermetic local CONNECT proxy.

Result: 19 sync/async scenarios passed; 48 real mTLS requests carried a verified client certificate (24 token exchanges, 24 API requests). Scenarios cover pinned host/path and token JSON without subject_token, bearer injection, token caching, actual clock-based refresh, transient retry/Retry-After, 401 refresh/replay, non-replayable multipart uploads that invalidate rejected tokens without replay, typed with_options() client copies that preserve their effective mTLS transport, async single-flight and waiter cancellation, sync/async timeouts, exchange/API redirect refusal including overridden auth, malformed token JSON, OAuth-error redaction, and the original callable WorkloadIdentity public API.

Residual scope limitation: no customer-enrolled production identity provider was contacted or required; the independent end-to-end exchange uses a real local mutually authenticated TLS service with freshly generated certificates.

Current exact-head independent verification

Final independently verified head: 9512899eb98aab917ec9cf4c59342c77eb45c394; fresh mergeable base: 10ee3f0da2ac6f93345c1204bd7bb1a2faa79ff2 (zero commits behind).

  • Addressed all eight latest automated-review findings with 36 new sync/async regression cases: compare-and-invalidate rejected replay tokens; record and restore every seekable multipart upload's original file offset; support API-key-to-X.509 and X.509-to-API-key copies while preserving custom origins and resetting implicit defaults; prevent caller HTTP auth from leaking to the token endpoint or replacing exchanged API bearer tokens; explicitly reject X.509 identities from Azure copies; and reject malformed/missing-ID identities with typed errors. Each review thread has an exact fix explanation and is resolved.
  • Built both wheel and source distribution from this exact committed tree with rye build --clean, installed the wheel into a freshly created virtual environment, and ran an external consumer through public OpenAI / AsyncOpenAI with a native HTTPX2 transport, ephemeral CA/server/client certificates, and a hermetic local CONNECT proxy. 32 independently reproduced scenarios passed over 78 real client-certificate-verified HTTPS requests: 38 exact-origin token exchanges and 40 API requests. The exchange body never contains subject_token and never inherits caller Authorization; scenarios also prove actual BasicAuth suppression, bearer injection, cache reuse/real-time refresh, transient retry, 401 replay and rejected-replay invalidation, real seekable multipart upload replay, one-shot upload invalidation, bidirectional API-key/X.509 mode switching, redirect refusal, timeout, cancellation/single-flight, typed/redacted errors, malformed identity rejection, and Azure boundaries.
  • Ran the complete OpenAPI-mock-backed installed-wheel suite on every supported Python release: Python 3.10, 3.11, 3.12, 3.13, and 3.14 each passed 7,255 tests with 31 expected skips. The additional Python 3.10/Pydantic 1 suite passed 7,241 tests with 45 expected skips; the independently reproduced dedicated legacy HTTPX lane passed 130 tests.
  • ./scripts/lint passes Ruff, Pyright (0 errors / 0 warnings), mypy (1,547 source files), and import validation. Python support-policy validation, Python 3.9 wheel rejection, Bedrock wheel validation, HTTPX2/aiohttp/legacy wheel validation, README formatting, changed-file formatting, Python compilation, and git diff --check all pass.
  • The independently reproduced uv lock --check failure and one unrelated generated-file ruff format --check . failure are present unchanged on the exact upstream base; neither dependency locks nor generated baseline code were altered.
  • Strict thermo-nuclear maintainability review and a separate Python-idiom review found no remaining structural or compatibility blocker. Scope remains HTTP-only; Realtime/WebSockets are Phase 2, and no production endpoint or customer credentials were used.

@jbeckwith-oai
jbeckwith-oai requested a review from a team as a code owner August 15, 2026 08:20
@openai-sdks

openai-sdks Bot commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

OkTest Summary

237/237 SDK tests passed in 13.93s for Python SDK PR #3622.

Test results — 42 files
Test Result Time
tests/chat-completions-complex-body.test.ts ✅ Passed 265ms
tests/chat-completions-create.test.ts ✅ Passed 353ms
tests/chat-completions-stream.test.ts ✅ Passed 192ms
tests/files-content-binary.test.ts ✅ Passed 189ms
tests/files-create-multipart.test.ts ✅ Passed 226ms
tests/files-list-pagination.test.ts ✅ Passed 169ms
tests/initialize-config.test.ts ✅ Passed 162ms
tests/instance-isolation.test.ts ✅ Passed 289ms
tests/models-list.test.ts ✅ Passed 249ms
tests/responses-background-lifecycle.test.ts ✅ Passed 315ms
tests/responses-body-method-errors.test.ts ✅ Passed 526ms
tests/responses-cancel-timeout.test.ts ✅ Passed 264ms
tests/responses-cancel.test.ts ✅ Passed 398ms
tests/responses-compact-retries.test.ts ✅ Passed 424ms
tests/responses-compact.test.ts ✅ Passed 349ms
tests/responses-create-advanced-stream.test.ts ✅ Passed 228ms
tests/responses-create-advanced.test.ts ✅ Passed 336ms
tests/responses-create-disconnect.test.ts ✅ Passed 1.7s
tests/responses-create-errors.test.ts ✅ Passed 344ms
tests/responses-create-malformed-api-responses.test.ts ✅ Passed 496ms
tests/responses-create-retries.test.ts ✅ Passed 433ms
tests/responses-create-stream-failures.test.ts ✅ Passed 230ms
tests/responses-create-stream-timeout.test.ts ✅ Passed 251ms
tests/responses-create-stream-wire.test.ts ✅ Passed 4.081s
tests/responses-create-stream.test.ts ✅ Passed 134ms
tests/responses-create-terminal-states.test.ts ✅ Passed 372ms
tests/responses-create-timeout.test.ts ✅ Passed 263ms
tests/responses-create.test.ts ✅ Passed 467ms
tests/responses-delete.test.ts ✅ Passed 254ms
tests/responses-input-items-errors.test.ts ✅ Passed 514ms
tests/responses-input-items-list.test.ts ✅ Passed 370ms
tests/responses-input-items-options.test.ts ✅ Passed 407ms
tests/responses-input-tokens-count-timeout.test.ts ✅ Passed 337ms
tests/responses-input-tokens-count.test.ts ✅ Passed 422ms
tests/responses-malformed-inputs.test.ts ✅ Passed 3.159s
tests/responses-not-found-errors.test.ts ✅ Passed 385ms
tests/responses-parse.test.ts ✅ Passed 603ms
tests/responses-retrieve-retries.test.ts ✅ Passed 380ms
tests/responses-retrieve.test.ts ✅ Passed 381ms
tests/responses-stored-method-errors.test.ts ✅ Passed 867ms
tests/retry-behavior.test.ts ✅ Passed 3.237s
tests/sdk-error-shape.test.ts ✅ Passed 475ms

View OkTest run #31904046074

SDK merge (a104c95d3bd6) · head (edeba35fe8ad) · base (10ee3f0da2ac) · OkTest (7e7850017529)

Comment thread tests/test_x509_workload_identity.py Fixed
Comment thread tests/test_x509_workload_identity.py Fixed

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

Copy link
Copy Markdown

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: d83f5cb658

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/openai/_client.py Outdated
Comment thread src/openai/auth/_workload.py Outdated
Comment thread src/openai/_client.py Outdated
Comment thread src/openai/auth/_workload.py Outdated
Comment thread src/openai/auth/_x509.py
Comment thread src/openai/auth/_x509.py Fixed

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

Copy link
Copy Markdown

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: 55e1460da3

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/openai/_client.py
Comment thread src/openai/_client.py Outdated

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

Copy link
Copy Markdown

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: 5df57ae901

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/openai/_client.py Outdated
Comment thread src/openai/lib/azure.py
Comment thread src/openai/_client.py Outdated
Comment thread src/openai/auth/_x509.py Outdated

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

Copy link
Copy Markdown

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: 2252fbe80f

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/openai/auth/_x509.py
Comment thread src/openai/_client.py
Comment thread src/openai/_client.py

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

Copy link
Copy Markdown

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: 2e426fa535

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/openai/_client.py Outdated
@jbeckwith-oai

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Security review completed. No security issues were found in this pull request.

Reviewed commit: 9512899eb9

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

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

Copy link
Copy Markdown

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: 145d3f2a02

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/openai/_client.py Outdated

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

Copy link
Copy Markdown

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: fe8d0652b4

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/openai/auth/_x509.py Outdated
@jbeckwith-oai

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Security review completed. No security issues were found in this pull request.

Reviewed commit: fe8d0652b4

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

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

Copy link
Copy Markdown

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: fe8d0652b4

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/openai/auth/_x509.py Outdated
Comment thread src/openai/_client.py
@jbeckwith-oai

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Security review completed. No security issues were found in this pull request.

Reviewed commit: eb39b75108

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

@jbeckwith-oai

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Bravo.

Reviewed commit: edeba35fe8

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@chatgpt-codex-connector

Copy link
Copy Markdown

Security review completed. No security issues were found in this pull request.

Reviewed commit: edeba35fe8

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

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