Skip to content

Conversation

@vverman
Copy link
Contributor

@vverman vverman commented Jan 25, 2026

Contains changes for the feature Regional Access Boundary (Previously Called Trust Boundaries).

The following are salient changes:

Calls to refresh RAB are now all async and in a separate thread.
Logic for refreshing RAB now exists in its own class for cleaner maintenance.
Self-signed jwts are within scope.
Changes to how we trigger RAB refresh and deal with refresh errors.

@vverman vverman requested review from a team as code owners January 25, 2026 21:35
@vverman vverman requested a review from a team January 25, 2026 21:35
@product-auto-label product-auto-label bot added the size: xl Pull request size is extra large. label Jan 25, 2026
@vverman vverman requested review from lqiu96 and nbayati January 25, 2026 21:49
@lqiu96 lqiu96 changed the base branch from feat-tb-sa to feat/agentic-identities-cloudrun February 3, 2026 19:16
@lqiu96 lqiu96 requested a review from a team as a code owner February 3, 2026 19:16
try {
// Check for the stale regional access boundary error message in the response body.
// Note: This consumes the response stream.
String content = response.parseAsString();
Copy link
Member

Choose a reason for hiding this comment

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

I think this should be fine since this is part of the flow to initialize this request. But if it consumes the content and closes the stream, I wonder if this may break anything that tries to consume it later.

Copy link
Contributor Author

@vverman vverman Feb 7, 2026

Choose a reason for hiding this comment

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

There is no easy way to create a copy of an HTTPResponse, in order to peek into its contents we have to consume the response stream.

However, before consuming the error:

  1. The HTTP code is a 406 which is relatively uncommon
  2. The request actually carried RAB headers

This should ensure that for the majority of scenarios this downstream error won't be a problem.

Copy link
Member

Choose a reason for hiding this comment

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

I set up a sync with you tomorrow to discuss this. I have a bit of concerns for this, but not for the reasons above. I'll create a doc with questions and share with you to review prior to the meeting

// this thread "won the race" and is responsible for starting the background task.
// All other concurrent threads will return false and exit immediately.
if (refreshFuture.compareAndSet(null, future)) {
CompletableFuture.runAsync(
Copy link
Member

Choose a reason for hiding this comment

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

Can you use Guava's ListeningFuture to keep with the rest of the auth-library?

Since this is called from both getReqestMetadata(...) methods (one of which takes in an executor), I think we'll also need to respect that.

I think this method should take in the executor as a param

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The way I understand: the executor in getRequestMetadataAsync is used to provide a pool of threads to execute the token refresh in the background.

My initial assumption with doing this via CompletableFuture was that the user might want the background thread to exclusively focus on token refresh and not the RAB refresh.

If we are okay with the user's background thread waiting longer for the RAB to refresh then I am okay with making this change.

Copy link
Member

Choose a reason for hiding this comment

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

I see, that's a good point. The async executor is intended to not block the calling thread while getting the headers (before the only headers was just the access token).

I believe the ideal state would as you're mentioning:
Sync: Main thread blocks for the token call, then rab would be a different async executor thread
async: async executor thread would run the token call, then rab would any async executor thread (even the same one)

Looks like CompletableFuture uses ForkJoinPool.commonPool() which wouldn't be ideal for IO bound tasks. Also looks like it's a static shared executor for the entire JVM which may impact other processes.

I think I'm leaning with having the background task wait for the RAB call.

}

/**
* Refreshes the Regional Access Boundary if it is expired or not yet fetched.
Copy link
Member

Choose a reason for hiding this comment

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

nit: the method name and docs isn't fully accurate as it does more than just checking if the boundary has expired.

If possible, can this be broken into two methods:

  1. shouldRefresh...()
  2. refresh...()

I think it might be easier to test as well. Let me know what you think

@vverman vverman changed the base branch from feat/agentic-identities-cloudrun to feat-tb-sa February 6, 2026 22:40

/**
* Returns the trust boundary URI.
* Returns the regional access boundary URI.
Copy link
Member

Choose a reason for hiding this comment

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

Can you add that this URL is constructed only for GDU

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

Labels

size: xl Pull request size is extra large.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants