# fix(coreapi): assert token_exchange_url path in validateExchangeURL

`4a937e7`→[main](/content/gh/entireio/cli/commits/main/index.html)·

toothbrush·4w ago·2 files·+10 added/-0 removed

exchangeSubjectToken strips oauthTokenPath and PostOAuthToken re-appends
it, but validateExchangeURL only gated scheme and host. A hint whose path
wasn't /oauth/token would make the strip a no-op and POST to a
server-chosen path. Validate the path so the round-trip is honest.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

## Sessions

ea9e8dae6384View transcript

[?\
Review PR Comments on Cross-Jurisdiction RoutingClaude Code·Opus 4.8[1m]·2 steps](/content/gh/entireio/cli/session/2d6d6a51-951b-44ac-be1b-df81b4957e30#timeline-ea9e8dae6384/index.html)

## Changes

2

- internal/coreapi

- Mcross_juris_transport.go+7

- Mcross_juris_transport_test.go+3

```
338 unmodified lines

339
340
341
342
343
344
345
346
347
348
11 unmodified lines

360
361
362
363
364
365
366
367
368

338 unmodified lines

//     core's /oauth/token always lives on the same origin as its
//     middleware; off-origin hints have no legitimate use and would
//     let a misconfigured / hostile core exfiltrate the user's JWT.
//   - Path must be exactly oauthTokenPath. exchangeSubjectToken strips
//     that suffix and PostOAuthToken re-appends it; validating it here
//     keeps that round-trip honest instead of silently POSTing to a
//     server-chosen path.
func validateExchangeURL(raw string, requestURL *url.URL) error {
	if raw == "" {
		return errors.New("token_exchange_url missing")
11 unmodified lines

if exchange.Host != requestURL.Host {
		return fmt.Errorf("token_exchange_url host %q must match response host %q", exchange.Host, requestURL.Host)
	}
	if exchange.Path != oauthTokenPath {
		return fmt.Errorf("token_exchange_url path %q must be %q", exchange.Path, oauthTokenPath)
	}
	return nil
}
```

Minternal/coreapi/cross_juris_transport.go+7

```
415 unmodified lines

416
417
418
419
420
421
422
423
424

415 unmodified lines

if err := validateExchangeURL("http://localhost:1234/oauth/token", mustParse("http://localhost:1234/api")); err != nil {
		t.Errorf("loopback http must pass: %v", err)
	}
	if err := validateExchangeURL("https://example.test/auth/x", mustParse("https://example.test/api")); err == nil {
		 t.Error("non-/oauth/token path must be refused")
	}
}// TestRoundTripper_TokenCacheReusesExchanged confirms the per-origin
```
