Repository navigation
fix(sync): keep sync token management authenticated when login is disabled - #17053
Merged
diegosouzapw merged 2 commits intoOct 18, 2026
Merged
Conversation
… login is disabled Co-authored-by: gsmarcil <116014240+gsmarcil@users.noreply.github.com>
…abled Co-authored-by: gsmarcil <116014240+gsmarcil@users.noreply.github.com>
Contributor
CI Coverage Report
Coverage artifact was not available for this run. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
A sync token opens
GET /api/sync/bundle, which returns decrypted provider credentials and plaintext API keys — the same material/api/settings/export-jsonhands out. That export route stays authenticated when login is disabled, but sync token management did not:requireLogin=false,POST /api/sync/tokenstreated "login is off" as the operator (issuedBy: "open"), so a caller with no credential at all could mint a token and read the bundle.Fix
authorizeSyncTokenIssuer()passesalwaysRequireAuth: truetorequireOperatorCredential()(option added in fix(relay): make relay token minting operator-only and sanitize its error path #17032): issuing a sync token needs a signed-in dashboard session, the local CLI or the trusted internal service in every login mode. A manage-scoped API key keeps getting403, an anonymous caller now gets401in open mode too.GET /api/sync/tokens(list) andDELETE /api/sync/tokens/{id}(revoke) userequireManagementAuth(..., { alwaysRequireAuth: true }), and/api/sync/tokensjoinsALWAYS_PROTECTED_API_PATHS(prefix covers the[id]child) with the matchingx-always-protectedOpenAPI annotations./api/sync/bundlestays a public route: it authenticates with the sync token itself.validateSyncToken()refuses any token recorded asissuedBy: "open": nothing vouches for its holder, so those rows never open the bundle again. Tokens issued by a session, the CLI or the internal service — and pre-issuer legacy rows (issuedBy: null, still bound to the password cutoff and their API key) — are unaffected.Behaviour change
Operators who run with login disabled and issued sync tokens from the dashboard without a session must issue them again from a signed-in session or the local CLI (
omniroute sync …); previously issuedopentokens stop working.Tests
tests/unit/sync-token-open-mode.test.ts(8 cases: anonymous issuance/list/revoke refused in open mode, manage key still 403, session and local CLI still issue working tokens with the rightissuedBy, a legacyopentoken never opens the bundle with login off or back on, other issuers unaffected) — written first; 7/8 red on the base with the exact symptoms (201 issuedBy=open, bundle200).tests/unit/authz/credential-export-always-protected.test.ts:/api/sync/tokens(+[id], trailing slash) added to the hard-gated inventory; new case proving the prefix stops before/api/sync/bundle,/api/sync/cloudand/api/sync/initialize.