Skip to content

fix(sync): keep sync token management authenticated when login is disabled - #17053

Merged
diegosouzapw merged 2 commits into
release/v3.8.52from
fix/sec-sync-token-open-mode-20261018
Oct 18, 2026
Merged

diegosouzapw merged 2 commits into
release/v3.8.52from
fix/sec-sync-token-open-mode-20261018

Conversation

@diegosouzapw

Copy link
Copy Markdown
Collaborator

⚠️ base-red inherited: #15306

What

A sync token opens GET /api/sync/bundle, which returns decrypted provider credentials and plaintext API keys — the same material /api/settings/export-json hands out. That export route stays authenticated when login is disabled, but sync token management did not:

  • With requireLogin=false, POST /api/sync/tokens treated "login is off" as the operator (issuedBy: "open"), so a caller with no credential at all could mint a token and read the bundle.
  • Turning login back on did not end those tokens: they kept opening the bundle, including credentials and manage-scoped keys created afterwards.

Fix

  • authorizeSyncTokenIssuer() passes alwaysRequireAuth: true to requireOperatorCredential() (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 getting 403, an anonymous caller now gets 401 in open mode too.
  • GET /api/sync/tokens (list) and DELETE /api/sync/tokens/{id} (revoke) use requireManagementAuth(..., { alwaysRequireAuth: true }), and /api/sync/tokens joins ALWAYS_PROTECTED_API_PATHS (prefix covers the [id] child) with the matching x-always-protected OpenAPI annotations. /api/sync/bundle stays a public route: it authenticates with the sync token itself.
  • validateSyncToken() refuses any token recorded as issuedBy: "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 issued open tokens stop working.

Tests

  • New 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 right issuedBy, a legacy open token 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, bundle 200).
  • 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/cloud and /api/sync/initialize.

diegosouzapw and others added 2 commits October 18, 2026 08:25
… login is disabled

Co-authored-by: gsmarcil <116014240+gsmarcil@users.noreply.github.com>
…abled

Co-authored-by: gsmarcil <116014240+gsmarcil@users.noreply.github.com>
@github-actions

Copy link
Copy Markdown
Contributor

CI Coverage Report

  • Coverage job: skipped
  • PR test policy: success

Coverage artifact was not available for this run.

@diegosouzapw
diegosouzapw merged commit 44a2961 into release/v3.8.52 Oct 18, 2026
34 of 51 checks passed
@diegosouzapw
diegosouzapw deleted the fix/sec-sync-token-open-mode-20261018 branch October 18, 2026 15:37
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.

1 participant