Skip to content

feat(oauth2): support mTLS dynamic certificate rotation and 401 retry - #13986

Draft
macastelaz wants to merge 13 commits into
googleapis:oauth2-bound-tokensfrom
macastelaz:cert-bound-oauth-part3
Draft

feat(oauth2): support mTLS dynamic certificate rotation and 401 retry#13986
macastelaz wants to merge 13 commits into
googleapis:oauth2-bound-tokensfrom
macastelaz:cert-bound-oauth-part3

Conversation

@macastelaz

@macastelaz macastelaz commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

mTLS Dynamic Certificate Rotation & STS 401 Retry Loop

Note to Reviewers:
This PR is stacked on top of PR #13955 (cert-bound-oauth-part2) and targets the upstream oauth2-bound-tokens feature branch.

🔍 To review only the incremental Phase 4 diffs cleanly while #13955 is pending, see:
macastelaz/google-cloud-java: compare cert-bound-oauth-part2...cert-bound-oauth-part3

Overview

This PR implements the portion of the Cert-Bound OAuth2 Design Document (go/java-auth-cert-bound-oauth2) which specifies the introduction of dynamic client certificate rotation for mutual TLS (mTLS) transports and an automatic 401 Unauthorized retry loop for Security Token Service (STS) token exchanges.

Key Changes

  1. Dynamic Certificate Rotation in MtlsHttpTransportFactory (google-auth-library-oauth2-http):

    • Added MtlsHttpTransportFactory(MtlsProvider mtlsProvider) constructor to accept a dynamic certificate provider (such as X509Provider).
      • Implemented public synchronized void rebuildContext() to reload
        client certificates and private keys from disk on demand.
      • Added an internal DelegatingSSLSocketFactory so existing NetHttpTransport instances automatically delegate socket creation (createSocket(...)) to the latest reloaded SSL socket factory without requiring transport reconstruction.
  2. Credential Initialization in IdentityPoolCredentials:

    • Updated both file-based and certificate-based certificate modes to pass new MtlsHttpTransportFactory(x509Provider) directly so credentials benefit from dynamic certificate reloading.
  3. STS 401 Unauthorized Retry Handler in ExternalAccountCredentials & StsRequestHandler:

    • Added .setUnsuccessfulResponseHandler(...) support to StsRequestHandler.Builder.
    • Wired a stateful HttpUnsuccessfulResponseHandler in ExternalAccountCredentials.exchangeExternalCredentialForAccessToken(). When an STS exchange over an mTLS transport returns 401 Unauthorized, the interceptor invokes ((MtlsHttpTransportFactory) transportFactory). rebuildContext() and retries the exchange once per token refresh cycle.

Testing & Verification

  • New Unit Tests:
    • Added MtlsHttpTransportFactoryTest verifying constructor null checks, KeyStore initialization, MtlsProvider initialization, and dynamic rebuildContext() delegate reloading.
    • Added ExternalAccountCredentialsTest#exchangeExternalCredentialForAccessToken_withMtls401_retriesAndRebuildsContext verifying that an initial 401 Unauthorized response from STS over an mTLS transport triggers rebuildContext() and succeeds on retry.
  • Test Suite Status:
    • All 960 unit tests in google-auth-library-java/oauth2_http pass (BUILD SUCCESS).
    • Verified IdentityPoolCredentialsTest passes cleanly.
  • Formatting & Style:
    • Strictly adheres to Google Java Format (< 100 character line length limit).
    • Clean git diff --check with 0 whitespace warnings.

Implementation of Phase 1-3 of the Cert-Bound Oauth2 Design Document:
1. Extend IdentityPoolCredentialSource to parse actorTokenFieldName.
2. Relax mutual exclusivity to allow BOTH file and certificate configurations.
3. Parse actor_token_type in ExternalAccountCredentials.
4. Refactor FileIdentityPoolTokenSupplier and track file timestamp via volatile CachedFile for the parsed JSON payload.
5. Inject actor_token and actor_token_type into StsTokenExchangeRequest using ActingParty.
6. Enforce that actor token extraction requires an mTLS STS configuration.
Fixes test failures and thread synchronization bugs regarding actor token credentials from https://paste.googleplex.com/5381957298028544
… for STS token exchange

Implementation of Phase 4 of the Cert-Bound OAuth2 Design Document (go/java-auth-cert-bound-oauth2):
1. Extend MtlsHttpTransportFactory to accept MtlsProvider (e.g. X509Provider) and implement rebuildContext() for dynamic KeyStore reloading when certificates are rotated on disk.
2. Implement DelegatingSSLSocketFactory in MtlsHttpTransportFactory so existing NetHttpTransport instances automatically delegate to the reloaded SSLSocketFactory.
3. Update IdentityPoolCredentials to initialize MtlsHttpTransportFactory with X509Provider instead of a static KeyStore.
4. Attach an HttpUnsuccessfulResponseHandler retry interceptor in ExternalAccountCredentials to detect 401 Unauthorized responses during mTLS STS token exchange, rebuild the SSL context, and retry once per refresh cycle.
5. Add unit tests in MtlsHttpTransportFactoryTest and ExternalAccountCredentialsTest.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces support for actor tokens and dynamic mTLS credential reloading within IdentityPoolCredentials. Key changes include the addition of an IdentityPoolActorTokenSupplier interface, the replacement of FileIdentityPoolSubjectTokenSupplier with a thread-safe, caching-enabled FileIdentityPoolTokenSupplier for both subject and actor tokens, and the implementation of a 401-retry mechanism that rebuilds the SSL context using a new DelegatingSSLSocketFactory in MtlsHttpTransportFactory. I have no feedback to provide as there are no review comments.

…NetHttpTransport return type on MtlsHttpTransportFactory.create()

Restores 100% binary bytecode compatibility for downstream Google Cloud client libraries (e.g. java-bigtable) while preserving dynamic SSL context rebuilding and STS 401 retry capabilities.
@macastelaz macastelaz changed the title Cert bound oauth part3 feat(oauth2): support mTLS dynamic certificate rotation and 401 retry Aug 4, 2026
@macastelaz macastelaz changed the title feat(oauth2): support mTLS dynamic certificate rotation and 401 retry feat(oauth2): support mTLS dynamic certificate rotation and 401 retry Aug 4, 2026
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