Skip to content

fix(auth): Route org token requests to region_url#3342

Closed
NicoHinderling wants to merge 2 commits into
masterfrom
fix/org-token-region-url-routing
Closed

fix(auth): Route org token requests to region_url#3342
NicoHinderling wants to merge 2 commits into
masterfrom
fix/org-token-region-url-routing

Conversation

@NicoHinderling

Copy link
Copy Markdown
Contributor

Summary

Org auth tokens (sntrys_) for multi-region SaaS orgs carry two hosts in their payload:

  • url — the control silo (https://sentry.io)
  • region_url — where the org's API requests are actually served (https://<region>.sentry.io)

The CLI only parsed url and discarded region_url entirely. For region-scoped org tokens (e.g. us2, s4s2), that meant region-siloed requests — like snapshots upload — were sent to the control silo and rejected with 401 Invalid org token. Decoded examples (both real region tokens):

{ "url": "https://sentry.io", "region_url": "https://us2.sentry.io", "org": "us2-test-org-sc" }
{ "url": "https://sentry.io", "region_url": "https://s4s2.sentry.io", "org": "sentry-s4s2" }

Passing --url did not help: when a token embeds a URL, the CLI overrides --url with the token's URL — so requests still went to sentry.io.

Fix

  • Parse region_url from the token payload (AuthTokenPayload).
  • Add a base_url() helper that prefers region_url, falling back to url when absent.
  • Use base_url() everywhere config.rs derives the API host (from_file, set_auth, set_base_url).

Result: every command routes to the correct region automatically, with no --url flag needed. Verified end-to-end — a snapshots upload to sentry-s4s2 now succeeds (previously 401).

Compatibility / behavior notes

  • Tokens where url == region_url (self-hosted, classic SaaS) and legacy tokens with no region_url are unaffectedbase_url() returns the same value as before.
  • Behavior change: a token with an empty url but a present region_url now routes to region_url and overrides --url, whereas it previously let --url take precedence. This is the correct behavior for region-scoped tokens and keeps the no-flag default routing to the right region.
  • This does not affect personal/user tokens, which carry no region info; those still rely on default routing or an explicit --url.

Tests

  • Unit tests for base_url() precedence: differing url/region_url, null url with present region_url, and a legacy token with region_url absent.
  • Integration (trycmd): new region-url-routing case asserting region_url is preferred over both the token's url and --url; updated url-mismatch-empty-token to reflect the new behavior.
  • Full unit suite (186) + org_tokens integration cases pass; clippy clean; cargo fmt applied.

Org auth tokens for multi-region SaaS orgs (e.g. us2, s4s2) embed a control-silo
url (https://sentry.io) plus a region_url (https://<region>.sentry.io) that serves
the org's API requests. The CLI only parsed url and discarded region_url, so
region-siloed requests such as snapshot uploads were sent to the control silo and
rejected with 401 Invalid org token.

Parse region_url from the token payload and prefer it as the base URL, falling back
to url when absent. This routes all commands to the correct region automatically,
with no need for a manual --url flag.

Tokens where url equals region_url (self-hosted, classic SaaS) are unaffected. A
token with an empty url but a present region_url now routes to region_url and
overrides --url, where it previously let --url take precedence.
@NicoHinderling NicoHinderling requested review from a team and szokeasaurusrex as code owners June 23, 2026 17:46
Adds the changelog entry required by Danger CI for #3342.
// Region URL is the host that actually serves this org's API requests. It is
// absent from older tokens, in which case requests fall back to `url`.
#[serde(default, deserialize_with = "url_deserializer")]
pub region_url: String,

@lcian lcian Jun 23, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
pub region_url: String,
pub region_url: Option<String>,

This would be the proper type, instead of using an empty string as a sentinel value

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

And I guess the reason the clanker used String is that we're gonna need a new opt_url_deserializer to do it that way

@NicoHinderling

Copy link
Copy Markdown
Contributor Author

@szokeasaurusrex this change enabled me to locally upload snapshots to us2 but im not 100% confident as i'm not working on the us2 project directly so ive shared this PR with that team and won't merge until they signoff too

Comment on lines +33 to +37
if self.region_url.is_empty() {
&self.url
} else {
&self.region_url
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This part makes sense to me as most CLI operations (and org auth tokens in general) work on regional resources. This would make it so that org-auth-tokens can't be used on anything that involves control though.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

+1 on this: Broadly switching all operations to prefer the region URL could be risky; we should validate that all endpoints supported by org auth tokens also are available on the region.

Less risky could be to expose a way to get the region URL while still maintaining a way to get the base URL, although that is likely a bit complex. That would allow us to use the region URL where needed and for commands where we have validated that it works, while continuing to use the base URL elsewhere.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I noticed that an old version of CLI had this utility

pub fn region_specific(&'a self, org: &'a str) -> RegionSpecificApi<'a> {

Maybe relevant for the discussion here?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Yeah, we had used this for the pre-chunked-uploading uploads that were removed in Sentry CLI 3.x. We no longer needed it for chunked uploads, as the chunked upload endpoint already returns the region-specific URL as the upload URL, which is why this was removed.

If we go with a fix in the CLI, though, we might want something like this utility so that we only migrate the API calls that need to go to the region-specific endpoints over to the region specific URLs; that lowers the risk of this change by keeping most things on control silo.

@NicoHinderling

Copy link
Copy Markdown
Contributor Author

We can avoid doing this by changing the nginx routing logic fortunately. i didn't fully deploy the changes yesterday and something broke

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.

4 participants