Skip to content

fix(security): image loader uses a credential-free client (CDN auth confirmed)#39

Merged
SiteRelEnby merged 2 commits into
mainfrom
fix/credential-origin-and-session-teardown
Jul 15, 2026
Merged

fix(security): image loader uses a credential-free client (CDN auth confirmed)#39
SiteRelEnby merged 2 commits into
mainfrom
fix/credential-origin-and-session-teardown

Conversation

@SiteRelEnby

@SiteRelEnby SiteRelEnby commented Jul 15, 2026

Copy link
Copy Markdown
Collaborator

Follow-up to #37, tightening the credential posture now that the CDN auth model is confirmed.

  • Server (sheaf): the file serve path GET /v1/files/{path} has no auth dependency. Images are
    authorised by an HMAC signature in the URL (?token=&expires=, image_serving defaults to signed,
    ~1h window). Images are public-by-URL, not per-user access-controlled. file_cdn_base is
    settings.s3_public_url, returned from the public /v1/auth/config.
  • Infra (sheaf-infra, cf-image-worker): in production, image URLs point at images.sheaf.sh, and the
    Cloudflare worker validates only the in-URL HMAC (token/expires/key-prefix). It never inspects
    Authorization and only allows GET/HEAD. The backend signs; the worker verifies.
  • The image loader gets its own standalone OkHttp client with no auth stack - no AuthInterceptor, no
    CF-Access headers, no trusted-device cookie jar, no 401 token-refresh authenticator. Just the user-agent and
    the debug TLS trust for local dev servers (extracted to a shared applyDebugTls helper). Previously it was
    cloned from the API client and dragged all of that onto every avatar fetch - including ones to the CDN,
    which sent the users session through Cloudflares edge for nothing.
  • With images off the shared client, AuthInterceptor is tightened to the API origin only (the API
    client never fetches CDN URLs; this is now just defence in depth). Dropped the now-unused
    isTrustedCredentialOrigin helper.

Verification

  • :app:assemblePlayRelease :app:testPlayReleaseUnitTest green (162 tests).
  • Tests updated: the API client sends nothing to the CDN host or any external host; originMatches /
    sameConfiguredOrigin unchanged.

Confirmed against the server (sheaf) and infra (cf-image-worker): served images
are authorised entirely by an HMAC signature already in the URL
(?token=&expires=), verified by the API's /v1/files serve path or by the
Cloudflare image worker on the CDN host. They never need, and the worker never
checks, an Authorization header.

So instead of scoping the shared client's credentials to include the CDN origin,
the image loader now uses a standalone OkHttp client with no auth stack at all:
no AuthInterceptor, no CF-Access headers, no trusted-device cookie jar, no 401
token-refresh authenticator. It carries only the user-agent and the debug TLS
trust for local dev servers (extracted to a shared applyDebugTls helper). This
also stops the user's session transiting the CDN's Cloudflare edge for no reason.

With images off the shared client, AuthInterceptor no longer needs the CDN in
its trusted set, so it's tightened to the API origin only (defence in depth for
the API client itself). Dropped the now-unused isTrustedCredentialOrigin helper
and updated the tests to match: the API client sends nothing to the CDN or any
external host.
@SiteRelEnby
SiteRelEnby enabled auto-merge July 15, 2026 02:59
@SiteRelEnby
SiteRelEnby merged commit 8b10a1f into main Jul 15, 2026
1 check passed
@SiteRelEnby
SiteRelEnby deleted the fix/credential-origin-and-session-teardown branch July 15, 2026 03:04
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