Skip to content

Comments

feat: Regional Access Boundary Changes#891

Open
vverman wants to merge 13 commits intogoogleapis:trust_boundaryfrom
vverman:trust-boundary-upto-speed
Open

feat: Regional Access Boundary Changes#891
vverman wants to merge 13 commits intogoogleapis:trust_boundaryfrom
vverman:trust-boundary-upto-speed

Conversation

@vverman
Copy link
Contributor

@vverman vverman commented Jan 17, 2026

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

The following are salient changes:

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

@vverman vverman requested a review from a team as a code owner January 17, 2026 01:31
* @throws {Error} If the URL cannot be constructed for a compatible client.
*/
protected async getTrustBoundaryUrl(): Promise<string | null> {
public async getRegionalAccessBoundaryUrl(): Promise<string | null> {
Copy link

Choose a reason for hiding this comment

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

Why this method became public?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I made it so for ease of testing the getRegionalAccessBoundaryUrl logic. For ex: in the base external client we have scenarios where we want to test if the right url is returned or error is thrown in case of workload, workforce or a null audience.

Copy link
Contributor

Choose a reason for hiding this comment

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

I'd go ahead and put an @private on it, as that will cause it to be omitted from docs, but it will still show up in the transpiled class. Anyone digging in the source can see the @private to know they shouldn't use it.

Actually, it looks like @internal omits it from any exported .d.ts, so that may be enough. I'd double-check the output though, to see what it makes.

Copy link

Choose a reason for hiding this comment

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

@vverman +1 to using @internal if you can verify that it's omitted from docs and transpiled classes.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

While @internal removes it from the type definitions, it doesn't remove it from the transpiled classes aka the .js files since they are needed for the logic to execute at runtime.

However if they are removed from the type definitions i.e. the d.ts type files a user cannot easily discover them as they wouldn't show up in their intellisense.

@vverman vverman force-pushed the trust-boundary-upto-speed branch from 238aed8 to f40a3e1 Compare January 29, 2026 02:12
…e requestAsync level. RAB urls now have googleapis as universe domain.
@vverman vverman force-pushed the trust-boundary-upto-speed branch from e3e00da to 3427c0e Compare January 29, 2026 19:14
@vverman vverman requested a review from nbayati January 30, 2026 21:00
Copy link
Contributor

@feywind feywind left a comment

Choose a reason for hiding this comment

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

I don't see anything too weird in this, I guess let me know when you've got one that merges against main?

* @throws {Error} If the URL cannot be constructed for a compatible client.
*/
protected async getTrustBoundaryUrl(): Promise<string | null> {
public async getRegionalAccessBoundaryUrl(): Promise<string | null> {
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd go ahead and put an @private on it, as that will cause it to be omitted from docs, but it will still show up in the transpiled class. Anyone digging in the source can see the @private to know they shouldn't use it.

Actually, it looks like @internal omits it from any exported .d.ts, so that may be enough. I'd double-check the output though, to see what it makes.

@miguelvelezsa miguelvelezsa removed their assignment Feb 5, 2026
* @param url The URL to check.
*/
private isGlobalEndpoint(url: string | URL): boolean {
const hostname = url instanceof URL ? url.hostname : new URL(url).hostname;
Copy link

Choose a reason for hiding this comment

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

new URL(url) will throws a TypeError if the url string is a relative URL, or a malformed one.
We need to gracefully handle those cases by assuming they are global.

* @throws {Error} If the URL cannot be constructed for a compatible client.
*/
protected async getTrustBoundaryUrl(): Promise<string | null> {
public async getRegionalAccessBoundaryUrl(): Promise<string | null> {
Copy link

Choose a reason for hiding this comment

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

@vverman +1 to using @internal if you can verify that it's omitted from docs and transpiled classes.

async getRequestHeaders(url?: string | URL): Promise<Headers> {
const headers = (await this.getRequestMetadataAsync(url)).headers;
const {headers, isIDToken} = await this.getRequestMetadataAsync(url);
if (!isIDToken) {
Copy link

Choose a reason for hiding this comment

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

idtoken client overrides getRequestMetadataAsync is not returning isIDToken=true.
IIUC, IdTokenClient inherits the default getRegionalAccessBoundaryUrl (which returns null), so RAB lookup happen for idtoken and we won't attach the header anyway, but I think setting this flag explicitly ensures we skip the RAB logic entirely and avoids unnecessary checks and future-proofs against changes in the base classes.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Made the change to IdToken client now passes back isIDtoken flag.

My only concern with this was that implementing a flag to explicitly exclude a client would mean we have to include all the clients like refreshclient (for long living Authorized user workflows).

However considering we're already implementing a flag for id-token I am okay with IdTokenClient explicitly returning a flag.

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.

5 participants