Skip to content

[HOLD] Reauthenticate images only after confirmed authentication failures - #105300

Draft
rlinoz wants to merge 10 commits into
rodrigo-image-auth-head-pipelinefrom
rodrigo-image-auth-recovery
Draft

rlinoz wants to merge 10 commits into
rodrigo-image-auth-head-pipelinefrom
rodrigo-image-auth-recovery

Conversation

@rlinoz

@rlinoz rlinoz commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

Explanation of Change

Load authenticated images with their existing credentials instead of starting reauthentication from a client-side session-age estimate. After a load failure, reuse already-updated credentials or confirm HTTP 401 with an authenticated HEAD request before entering the existing authentication flow; preserve successful image sources so routine token updates do not reload them.

Deploy the companion backend change first so rejected image-token requests return 401 without a login redirect.

Fixed Issues

For https://github.com/Expensify/Expensify/issues/696902
$ #105498
PROPOSAL: N/A (internal change)

Tests

  1. Sign in with a test account, open a DM, and send a text message.
  2. Send two image attachments (a JPG and a PNG). Verify both render and that each image request carries the X-Chat-Attachment-Token header.
  3. In the console, save the current session: const old = await Onyx.get('session').
  4. In a second browser profile, sign in as the same account and call the classic SignOut API with the second session's own authToken. This revokes every token for the account. NewDot's own sign-out (LogOut) only deletes its device login and does not revoke other sessions.
  5. Back in the first browser, the revocation push triggers ReconnectApp, which returns 407 and reauthenticates through the API middleware. Verify the images already on screen are not requested again.
  6. To force the image-first path, run await Onyx.merge('session', {authToken: old.authToken, encryptedAuthToken: old.encryptedAuthToken}); await caches.delete('auth-images');, then open an image in the attachment viewer. old is now a server-revoked token.
  7. Verify this sequence:
    • the image GET returns 401;
    • a HEAD to the same URL returns 401;
    • exactly one Authenticate runs, even though the viewer also loads the neighbouring image;
    • the image GET is retried with a new token, returns 200, and the image displays.
  8. Repeat step 6, but instead of opening the viewer, switch to another chat and back so the thumbnails remount. API requests and images now detect the expiry at the same time. Verify exactly one Authenticate runs and the thumbnails load.
  9. Make one attachment URL return 404, clear auth-images, and remount the chat. Verify the HEAD check returns 404, no Authenticate runs, and the broken-image placeholder is shown.
  10. Send another message and verify it posts with the refreshed session.
  • Verify that no errors appear in the JS console

Offline tests

  1. Load an authenticated image while online.
  2. Disconnect the network and open another image.
  3. Confirm no authentication probe or reauthentication is started while the app knows it is offline.
  4. Restore the network connection.
  5. Confirm image loads can restart without a session-age-triggered sign-in.

QA Steps

Test 1 steps

  1. open a chat
  2. send a text + image as comment if you dont have it already
  3. click to edit the comment
  4. copy the comment
  5. send the copy as new comment
  6. observe the preview image displayed correctly

Test 2 steps

  1. open a chat
  2. send an image
  3. open the devtools console
  4. run the following code in the console to simulate expiring the session tokens :

Onyx.merge('session', {authToken: 'pizza', encryptedAuthToken: 'pizza', creationDate: new Date().getTime() - 236001000});

  1. observe the attachment preview does not display a gray box
  2. observe the attachment preview reloads while displaying a loading spinner

Note : on native platforms, the troubleshooting test tool "Authentication Status/Invalidate with delay" can be used to simulate expiring the session in the next 15 seconds when clicked.

Test 3 steps

  1. open a chat
  2. send an image
  3. click on the image to display it in the carousel
  4. open the devtools console
  5. run the following code in the console to simulate expiring the session tokens :

Onyx.merge('session', {authToken: 'pizza', encryptedAuthToken: 'pizza', creationDate: new Date().getTime() - 236001000});

  1. Observe the attachment image does not display a gray box
  2. Observe the attachment image reloads while displaying a loading spinner

Note : on native platforms, the troubleshooting test tool "Authentication Status/Invalidate with delay can be used to simulate expiring the session in the next 15 seconds when clicked.

  • Verify that no errors appear in the JS console

Screenshots/Videos

Android: Native
Android: mWeb Chrome
iOS: Native
iOS: mWeb Safari
MacOS: Chrome / Safari

Step 2: JPG attachment sent and rendered

JPG attachment sent and rendered with the session token

Step 2: PNG attachment sent and rendered

PNG attachment sent and rendered

Steps 6-7: attachment viewer loading with the revoked token (GET 401, then HEAD 401)

Attachment viewer loading with a server-revoked token

Steps 6-7: after one Authenticate, the retry with the new token returns 200 and the image displays

Attachment viewer after image-triggered reauthentication

Step 8: thumbnails remounting with the revoked token

Chat thumbnails remounting with a revoked token

Step 8: thumbnails loaded after one shared Authenticate

Chat thumbnails after shared reauthentication

Step 9: a 404 shows the broken-image placeholder, with no Authenticate

Non-401 image failure shows the broken-image placeholder without reauthentication

Step 10: message sent after recovery

Message sent after recovery

@codecov

codecov Bot commented Oct 28, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Looks like you've decreased code coverage for some files. Please write tests to increase, or at least maintain, the existing level of code coverage. See our documentation here for how to interpret this table.

Files with missing lines Coverage Δ
src/components/Image/getImageSource.ts 100.00% <100.00%> (ø)
.../actions/Session/AttachmentImageReauthenticator.ts 100.00% <100.00%> (+64.00%) ⬆️
src/libs/actions/Session/index.ts 68.60% <ø> (-0.12%) ⬇️
src/components/Image/index.tsx 92.30% <92.77%> (+27.22%) ⬆️
... and 8 files with indirect coverage changes

@rlinoz

rlinoz commented Oct 29, 2026

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 29, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-29T14:40:55.014875Z 4307077 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4307077a6c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@rlinoz
rlinoz changed the base branch from main to rodrigo-image-auth-head-pipeline October 29, 2026 22:40
@rlinoz
rlinoz added this pull request to stack #105431 October 29, 2026 22:40
@github-actions

This comment has been minimized.

@rlinoz rlinoz changed the title Reauthenticate images only after confirmed authentication failures [HOLD] Reauthenticate images only after confirmed authentication failures Oct 30, 2026

This branch has not been deployed

No deployments
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